假设我有以下简化表,其中有动态列a_x (其中x是索引,例如0、1、2、3、4.)分别为b_x。a列的数量总是等于b列的数量,但是列的总数可以是动态的(并不总是3 a和3 b)。为了更清楚地说明,下面的示例描述了我的数据结构:
> d <- read.table(text = "10 20 25 0.3 0.23 0.34
40 20 30 0.25 0.4 0.45")
> names(d) <- c("a_0", "a_1", "a_2", "b_0", "b_1", "b_2")
> d
a_0 a_1 a_2 b_0 b_1 b_2
1 10 20 25 0.30 0.23 0.34
2 40 20 30 0.25 0.40 0.45我希望将a列与相应的b列分开,并将结果保存到新的c列中。为了进行除法,我使用了transform()函数(带有硬编码的冒号),如下所示:
transform(d, c_0 = as.numeric(as.character(a_0)) / as.numeric(as.character(b_0)))考虑到输入数据的列数并不总是相同的事实,我如何使用(可能)冒名模式自动完成这一步骤。
如能提供任何帮助,将不胜感激。
发布于 2020-01-22 14:32:15
以下是几种方法。(1)和(1a)似乎最好,但其他方法确实显示了不同的方法。除(1a)和(2)外,它们的列名和顺序与问题相同,但如果这是一个问题,则可以很容易地加以修正。除(4a)外,不使用任何包。
1)变换
ix <- grep("a", names(d))
cbind(d, setNames(d[ix] / d[-ix], sub("a", "c", names(d)[ix])))
## a_0 a_1 a_2 b_0 b_1 b_2 c_0 c_1 c_2
## 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.666671a)这是(1)的一个变体;
transform(d, c = setNames(d[ix], ix-1) / d[-ix]) # ix is from above
## a_0 a_1 a_2 b_0 b_1 b_2 c.0 c.1 c.2
## 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.666672)将转换为长格式,执行除法,并将其转换回宽格式。
varying <- split(names(d), sub("_.*", "", names(d)))
long <- reshape(d, dir = "long", varying = varying, v.names = names(varying))
reshape(transform(long, c = a / b), dir = "wide", idvar = "id")[-1]
## a.1 b.1 c.1 a.2 b.2 c.2 a.3 b.3 c.3
## 1.1 10 0.30 33.33333 20 0.23 86.95652 25 0.34 73.52941
## 2.1 40 0.25 160.00000 20 0.40 50.00000 30 0.45 66.666673)应用,我们可以转换成三维数组,然后使用apply。
nr <- nrow(d)
nc <- ncol(d)
cc <- apply(array(as.matrix(d), c(nr, nc / 2, 2)), 1:2, function(x) x[1] / x[2])
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
## a_0 a_1 a_2 b_0 b_1 b_2 c_0 c_1 c_2
## 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.666674)将转置到d原木上,取差,再取exp转座子逆转原木转置。然后将其绑定到d。该解决方案假定所有条目都是严格正的(这是问题中的情况),这样我们就可以获取日志。
nc <- ncol(d)
cc <- t(exp(-diff(t(log(d)), nc/2)))
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
## a_0 a_1 a_2 b_0 b_1 b_2 c_0 c_1 c_2
## 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.66667(4a) diff.zoo支持几何差,它执行除法而不是减法。(在当前版本的动物园中,diff.zoo要求输入的元素严格为正,但在动物园的开发版本中取消了这一限制。)
library(zoo)
nc <- ncol(d)
cc <- 1 / t(diff(zoo(t(d)), nc/2, arith = FALSE))
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
## a_0 a_1 a_2 b_0 b_1 b_2 c_0 c_1 c_2
## x.1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## x.2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.66667发布于 2020-01-22 14:24:19
我们可以从名称中删除下划线后的所有内容,然后将它们分开,然后逐个分割。
Reduce(`/`, split.default(d, gsub('_.*', '', names(d))))
# a_0 a_1 a_2
#1 33.33333 86.95652 73.52941
#2 160.00000 50.00000 66.66667发布于 2020-01-22 14:30:40
您可以使用grep查找"a“和"b”列,并在transform中将结果添加为具有良好setNames的矩阵。
transform(d, ind=setNames(d[, grep("a", names(d))] / d[, grep("b", names(d))],
gsub(".*(\\D)", "", grep("a", names(d), value=T))))
# a_0 a_1 a_2 b_0 b_1 b_2 ind.0 ind.1 ind.2
# 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
# 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.66667https://stackoverflow.com/questions/59861786
复制相似问题