如何在R data.frame中创建组合变量?
我有一个data.frame,它有几个零值变量。我需要构造一个额外的变量,该变量将返回每个观测值不为零的变量组合。例如如何在R data.frame中创建组合变量?,r,dataframe,R,Dataframe,我有一个data.frame,它有几个零值变量。我需要构造一个额外的变量,该变量将返回每个观测值不为零的变量组合。例如 df <- data.frame(firm = c("firm1", "firm2", "firm3", "firm4", "firm5"), A = c(0, 0, 0, 1, 2), B = c(0, 1, 0, 42, 0), C = c(1, 1, 0, 0, 0
df <- data.frame(firm = c("firm1", "firm2", "firm3", "firm4", "firm5"),
A = c(0, 0, 0, 1, 2),
B = c(0, 1, 0, 42, 0),
C = c(1, 1, 0, 0, 0))
df使用应用:
# paste column names
df$varCombination <-
apply(df[,2:ncol(df)]>0, 1,
function(i)paste(colnames(df[, 2:ncol(df)])[i], collapse = "-"))
# convert blank to NA
df$varCombination[df$varCombination == ""] <- NA
# result
df
# firm A B C varCombination
# 1 firm1 0 0 1 C
# 2 firm2 0 1 1 B-C
# 3 firm3 0 0 0 <NA>
# 4 firm4 1 42 0 A-B
# 5 firm5 2 0 0 A
#粘贴列名
df$var0,1,
函数(i)粘贴(colnames(df[,2:ncol(df)])[i],collapse=“-”)
#将空白转换为NA
df$varCombination[df$varCombination==“”]使用apply(df,1,fun)
可能很容易解决这个问题,但为了性能起见,这里尝试按列而不是按行解决这个问题(我曾经看到@alexis_laz做过类似的事情,但现在找不到)
##创建一个逻辑矩阵
tmp您的想法正确,但循环中的逻辑比较不正确
我已尝试使代码与以前的代码非常相似,这应该可以:
var_names <- names(df)[-1]
df$varCombination <- character(nrow(df))
for (i in 1:nrow(df)){
non_zero_names <- var_names[df[i, -1] > 0]
df$varCombination[i] <- paste(non_zero_names, collapse = '-')
}
> df
firm A B C varCombination
1 firm1 0 0 1 C
2 firm2 0 1 1 B-C
3 firm3 0 0 0
4 firm4 1 42 0 A-B
5 firm5 2 0 0 A
var\u名称谢谢!到目前为止,所有建议的解决方案都非常有效。因此,选择你的版本作为最整洁的版本只是我个人喜好的问题。它缺少钠的替代物,但这不是绊脚石。@Antti这不仅仅是味道的问题。行操作是有控制的,因为R是一种矢量化语言,而且所有操作都是有控制的。您选择了迄今为止最慢的解决方案。在我的回答中看到一些基准。所以,请定义“neatest”,而你在它。@DavidArenburg我绝对同意,行式循环在R不是一个快速的解决方案。在我的辩护中,我确实认为循环让事情变得更清楚,我试图让它接近原始代码,这样询问者就更容易遵循逻辑。我也使用了循环。只是按列而不是按行。我的循环非常简单易读。因此,使用循环并不是一个真正的论点。不管怎样,我只是说OPs的评论对我来说没有多大意义。尽管如此,我并没有试图说服他接受任何一个答案。由他选择他喜欢的答案,我真的不在乎我的答案是否被接受。@DavidArenburg我想你是对的。你所做的基准使我信服。在我的实际应用程序中,节省的时间不会是微不足道的。我刚刚开始意识到直觉和效率之间的权衡。所以我还是会接受你的回答。干杯
# paste column names
df$varCombination <-
apply(df[,2:ncol(df)]>0, 1,
function(i)paste(colnames(df[, 2:ncol(df)])[i], collapse = "-"))
# convert blank to NA
df$varCombination[df$varCombination == ""] <- NA
# result
df
# firm A B C varCombination
# 1 firm1 0 0 1 C
# 2 firm2 0 1 1 B-C
# 3 firm3 0 0 0 <NA>
# 4 firm4 1 42 0 A-B
# 5 firm5 2 0 0 A
## Create a logical matrix
tmp <- df[-1] != 0
## or tmp <- sapply(df[-1], `!=`, 0)
## Prealocate result
res <- rep(NA, nrow(tmp))
## Run per column instead of per row
for(j in colnames(tmp)){
res[tmp[, j]] <- paste(res[tmp[, j]], j, sep = "-")
}
## Remove the pre-allocated `NA` values from non-NA entries
gsub("NA-", "", res, fixed = TRUE)
# [1] "C" "B-C" NA "A-B" "A"
set.seed(123)
BigDF <- as.data.frame(matrix(sample(0:1, 1e4, replace = TRUE), ncol = 10))
library(microbenchmark)
MM <- function(df) {
var_names <- names(df)[-1]
res <- character(nrow(df))
for (i in 1:nrow(df)){
non_zero_names <- var_names[df[i, -1] > 0]
res[i] <- paste(non_zero_names, collapse = '-')
}
res
}
ZX <- function(df) {
res <-
apply(df[,2:ncol(df)]>0, 1,
function(i)paste(colnames(df[, 2:ncol(df)])[i], collapse = "-"))
res[res == ""] <- NA
res
}
DA <- function(df) {
tmp <- df[-1] != 0
res <- rep(NA, nrow(tmp))
for(j in colnames(tmp)){
res[tmp[, j]] <- paste(res[tmp[, j]], j, sep = "-")
}
gsub("NA-", "", res, fixed = TRUE)
}
microbenchmark(MM(BigDF), ZX(BigDF), DA(BigDF))
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# MM(BigDF) 239.36704 248.737408 253.159460 252.177439 255.144048 289.340528 100 c
# ZX(BigDF) 35.83482 37.617473 38.295425 38.022897 38.357285 76.619853 100 b
# DA(BigDF) 1.62682 1.662979 1.734723 1.735296 1.761695 2.725659 100 a
var_names <- names(df)[-1]
df$varCombination <- character(nrow(df))
for (i in 1:nrow(df)){
non_zero_names <- var_names[df[i, -1] > 0]
df$varCombination[i] <- paste(non_zero_names, collapse = '-')
}
> df
firm A B C varCombination
1 firm1 0 0 1 C
2 firm2 0 1 1 B-C
3 firm3 0 0 0
4 firm4 1 42 0 A-B
5 firm5 2 0 0 A