【问题标题】:For each row extract the value in the column name that match another value in the cell对于每一行,提取与单元格中的另一个值匹配的列名中的值
【发布时间】:2021-03-27 09:32:14
【问题描述】:

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

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

数据框是这样的

> 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]), ] 

【问题讨论】:

标签: r dataframe dplyr apply sapply


【解决方案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”、“2”等来重命名列,
  • 不客气。很高兴为您提供帮助! @aichao 子集解决方案很棒而且非常快!如果你有一个非常大的数据集,它可能会更好用,我认为它可以很容易地适应字符索引(使用 factor(INDEX) ?)
  • @Toshiro:我已经用match 更新了答案,以将INDEX 中的数据与列名匹配。
  • @aichao:太好了!你是对的:使用 match 进行子集化是通用的并且非常快!对于庞大的数据集,我经常使用类似的技术而不是 merge。你的解决方案太棒了!
【解决方案2】:

你想要的可以通过以下方式实现:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多