对于每一行,提取列名称中与单元格中的另一个值匹配的值
For each row extract the value in the column name that match another value in the cell
我有一个问题可以用 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]), ]
根据您的循环,使用 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
你想要的可以通过以下方式实现:
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
我有一个问题可以用 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]), ]
根据您的循环,使用 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
你想要的可以通过以下方式实现:
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