我有一个大型数据框,其中包含未知的列名和数字值1、2、3或4。 现在,我想用其列名替换所有4个值,并用一个空值替换所有1、2和3。
当然,我可以进行某种循环,如下所示:
df <- data.frame(id=1:8,unknownvarname1=c(1:4,1:4),unknownvarname2=c(4:1,4:1))
for (i in 2:length(df)){
df[,i] <- as.character(df[,i])
df[,i] <- mgsub::mgsub(df[,i],c(1,2,3,4),c("","","",names(df)[i]))
}
这将是结果:
id unknownvarname1 unknownvarname2
1 1 unknownvarname2
2 2
3 3
4 4 unknownvarname1
5 5 unknownvarname2
6 6
7 7
8 8 unknownvarname1 unknownvarname2
对于这样大小的数据帧,这根本没有问题。但是,当我在具有多达30k和多达40个未知变量的大型数据帧上尝试执行此循环时,该循环需要花一些时间才能完成。
有人知道更快的方法吗?我尝试了类似mutate()
中的dplyr package
之类的功能,但无法使其正常工作。
非常感谢!
答案 0 :(得分:8)
使用基数R的一种方法
#Replace all the values with 1:3 with blank
df[-1][sapply(df[-1], `%in%`, 1:3)] <- ""
#Get the row/column indices where value is 4
mat <- which(df == 4, arr.ind = TRUE)
#Exclude values from first column
mat <- mat[mat[, 2] != 1, ]
#Replace remaining entries with it's corresponding column names
df[mat] <- names(df)[mat[, 2]]
df
# id unknownvarname1 unknownvarname2
#1 1 unknownvarname2
#2 2
#3 3
#4 4 unknownvarname1
#5 5 unknownvarname2
#6 6
#7 7
#8 8 unknownvarname1
答案 1 :(得分:7)
只需使用switch
给出另一个选项(尽管由于该函数未向量化,因此它需要在sapply
中嵌套lapply
而不会使它变得“漂亮”高效...):
基本上,switch
与numeric
作为switch(myNumberToTest, caseIfOne, caseIfTwo, ...)
一起使用。
所以您需要的是:
df[, 2:3] <- lapply(2:3, function(x) sapply(df[, x], switch, "", "", "", names(df)[x]))
df
# id unknownvarname1 unknownvarname2
#1 1 unknownvarname2
#2 2
#3 3
#4 4 unknownvarname1
#5 5 unknownvarname2
#6 6
#7 7
#8 8 unknownvarname1
答案 2 :(得分:7)
又一个基本的R选项,在lapply中使用ifelse(仍然在列上循环,但按列进行矢量化处理):
df <- data.frame(id=1:8,unknownvarname1=c(1:4,1:4),unknownvarname2=c(4:1,4:1))
df[,2:3] <- lapply(2:3, function(x) { ifelse(df[,x] < 4, "", colnames(df)[x]) })
给予
id unknownvarname1 unknownvarname2
1 1 unknownvarname2
2 2
3 3
4 4 unknownvarname1
5 5 unknownvarname2
6 6
7 7
8 8 unknownvarname1
答案 3 :(得分:6)
使用WHERE xColumn NOT LIKE 'AB-C%'
的另一个基数R可能性:
SQLCMD
给出:
sweep
这可以简化为:
idx <- df[, -1] == 4
sw <- sweep(idx, 2, 1:2, FUN = '*') + 1
df[, -1] <- c("", colnames(df[, -1]))[sw]
答案 4 :(得分:5)
效率较低的tidyverse
选项。这是低效的,因为我们需要稍后手动选择列:
to_use <- names(df)[-1]
df %>%
mutate_at(vars(contains("unknown")),list(~ifelse(.==4,
NA,
""))) -> new_df
new_df[-1] <-map2(new_df[-1], to_use,function(x,y) replace(x,is.na(x),y))
一种较不人工的方法,也具有不明确的缺点:
df %>%
map2(.,names(.), function(x, y) ifelse( x==4, y,"")) %>%
as.data.frame() %>%
mutate(id=row.names(.)) # might be a way around with `.id`
id unknownvarname1 unknownvarname2
1 1 unknownvarname2
2 2
3 3
4 4 unknownvarname1
5 5 unknownvarname2
6 6
7 7
8 8 unknownvarname1
方法1的结果
new_df
id unknownvarname1 unknownvarname2
1 1 unknownvarname2
2 2
3 3
4 4 unknownvarname1
5 5 unknownvarname2
6 6
7 7
8 8 unknownvarname1
答案 5 :(得分:5)
另一个使用B
排列名称和值的选项:
col