对于每一行,提取列名称中与单元格中的另一个值匹配的值

时间:2016-08-18 14:13:01

标签: r dataframe dplyr apply sapply

我有一个问题可以通过for循环轻松解决。但是,由于我在数据帧中有数十万行,这需要很长的计算时间,因此我正在寻找一种快速而智能的解决方案。

对于我的数据框中的每一行,我想粘贴其列名与第一列(INDEX)中的列匹配的单元格的值

数据框看起来像这样

> mydata
  INDEX    1   2    3   4    5   6
1     2 18.9 9.5 22.6 4.7 16.2 7.4
2     2 18.9 9.5 22.6 4.7 16.2 7.4
3     2 18.9 9.5 22.6 4.7 16.2 7.4
4     4 18.9 9.5 22.6 4.7 16.2 7.4
5     4 18.9 9.5 22.6 4.7 16.2 7.4
6     5 18.9 9.5 22.6 4.7 16.2 7.4

以下是复制它的代码:

mydata <- data.frame(INDEX=c(2,2,2,4,4,5), ONE=(rep(18.9,6)), TWO=(rep(9.5,6)), 
                     THREE=(rep(22.6,6)), FOUR=(rep(4.7,6)), FIVE=(rep(16.2,6)), SIX=(rep(7.4,6)))
colnames(mydata) <- c("INDEX",1,2,3,4,5,6)

这是带有新计算变量的新数据框:

> new_mydf
  INDEX    1   2    3   4    5   6 VARIABLE
3     2 18.9 9.5 22.6 4.7 16.2 7.4      9.5
2     2 18.9 9.5 22.6 4.7 16.2 7.4      9.5
1     2 18.9 9.5 22.6 4.7 16.2 7.4      9.5
5     4 18.9 9.5 22.6 4.7 16.2 7.4      4.7
4     4 18.9 9.5 22.6 4.7 16.2 7.4      4.7
6     5 18.9 9.5 22.6 4.7 16.2 7.4     16.2

我使用下面的for循环解决了它,但是,正如我上面所写,我正在寻找一个更直接的解决方案(可能使用像dplyr这样的软件包或其他函数?),因为循环对我来说很慢扩展数据集

id = mydata$INDEX
new_mydf <- data.frame()
for (i in 1:length(id)) {
  mydata_row <- mydata[i,]
  value <- mydata_row$INDEX
  mydata_row["VARIABLE"] <- mydata_row[,names(mydata_row) == value]
  new_mydf <- rbind(mydata_row,new_mydf)
}
new_mydf <- new_mydf[ order(new_mydf[,1]), ] 

2 个答案:

答案 0 :(得分:1)

根据您的循环,apply使用匿名函数可能会更快(使用mydata初始定义):

mydata$VARIABLE<-apply(mydata, 1, function(x) { x[names(x)==x[names(x)=="INDEX"]] })

编辑:它甚至可以在INDEX字符中使用:

mydata <- data.frame(INDEX=c("B","B","B","D","D","E"), "A"=(rep(18.9,6)), "B"=(rep(9.5,6)), 
                 "C"=(rep(22.6,6)), "D"=(rep(4.7,6)), "E"=(rep(16.2,6)), "F"=(rep(7.4,6)))

mydata$VARIABLE<-apply(mydata, 1, function(x) { x[names(x)==x[names(x)=="INDEX"]] })

> mydata INDEX A B C D E F VARIABLE 1 B 18.9 9.5 22.6 4.7 16.2 7.4 9.5 2 B 18.9 9.5 22.6 4.7 16.2 7.4 9.5 3 B 18.9 9.5 22.6 4.7 16.2 7.4 9.5 4 D 18.9 9.5 22.6 4.7 16.2 7.4 4.7 5 D 18.9 9.5 22.6 4.7 16.2 7.4 4.7 6 E 18.9 9.5 22.6 4.7 16.2 7.4 16.2

答案 1 :(得分:1)

您想要的是:

new_mydf <- data.frame(mydata, 
                       VARIABLE=mydata[cbind(seq_len(nrow(mydata)),
                                             match(as.character(mydata$INDEX),colnames(mydata)))])

这使用带索引的子集,这将比apply更快。例如,如果您的数据集是:

    INDEX Alpha Beta Charlie Delta Epsilon Foxtrot
1    Beta  18.9  9.5    22.6   4.7    16.2     7.4
2    Beta  18.9  9.5    22.6   4.7    16.2     7.4
3    Beta  18.9  9.5    22.6   4.7    16.2     7.4
4   Delta  18.9  9.5    22.6   4.7    16.2     7.4
5   Delta  18.9  9.5    22.6   4.7    16.2     7.4
6 Epsilon  18.9  9.5    22.6   4.7    16.2     7.4

这将给出:

    INDEX Alpha Beta Charlie Delta Epsilon Foxtrot VARIABLE
1    Beta  18.9  9.5    22.6   4.7    16.2     7.4      9.5
2    Beta  18.9  9.5    22.6   4.7    16.2     7.4      9.5
3    Beta  18.9  9.5    22.6   4.7    16.2     7.4      9.5
4   Delta  18.9  9.5    22.6   4.7    16.2     7.4      4.7
5   Delta  18.9  9.5    22.6   4.7    16.2     7.4      4.7
6 Epsilon  18.9  9.5    22.6   4.7    16.2     7.4     16.2

要进行基准测试,请模拟更大的数据集:

## simulate some data with 1000 columns and 1000 rows
INDEX <- ceiling(runif(1000,0,1000))
data <- rep(runif(1000,0,1), each=1000)
mydata <- data.frame(INDEX=INDEX,matrix(data,nrow=1000))
colnames(mydata) <- c("INDEX", seq_len(1000))

## using indexing
system.time(new_mydf <- data.frame(mydata, VARIABLE=mydata[cbind(seq_len(nrow(mydata)),match(as.character(mydata$INDEX),colnames(mydata)))]))
##   user  system elapsed 
##  0.030   0.001   0.031 

## using apply
system.time(mydata$VARIABLE<-apply(mydata, 1, function(x) { x[names(x)==x[names(x)=="INDEX"]] }))
##   user  system elapsed 
##  0.268   0.010   0.291 

## check that we computed the same thing
all.equal(mydata,new_mydf,check.names=FALSE)
##[1] TRUE