基于另一个数据框,从一个数据框中替换某些列的值

3

我有两个数据框(df1,df2),我想用df1$V2的值替换列P1-P10中的字母,但保留df2的前两列。

df1 = data.frame(V1=LETTERS, V2=rnorm(26))

df2 <- data.frame(Name=sample(LETTERS, 6), bd=sample(1:6), P1=sample(LETTERS,6), P2=sample(LETTERS, 6), P3=sample(LETTERS, 6), P4=sample(LETTERS, 6), P5=sample(LETTERS, 6), P6=sample(LETTERS, 6), P7=sample(LETTERS, 6), P8=sample(LETTERS, 6), P9=sample(LETTERS, 6), P10=sample(LETTERS, 6))

我的方法如下:

df3 <- matrix(setNames(df1[,2], df1[,1])[as.character(unlist(df2[,3:12]))], nrow=6, ncol=10)
df4 <- data.frame(cbind(df2[,1:2], df3))

这样可以得到我想要的输出结果,但是我的真实数据有10,000列,有没有什么方法可以避免使用cbind或者使整个过程更快?

> df4
Name bd         X1          X2         X3         X4         X5         X6        X7         X8         X9        X10
1    V  6 -1.8991102  0.40269050 -0.1517500 -2.5297829  1.5315622  1.4897071  1.364071 -1.2443708 -1.3197276 -0.4917057
2    T  1 -2.5297829 -0.44614123 -0.1894970 -0.6693774 -0.1517500 -1.0650962 -0.151750 -0.4461412 -0.6693774 -1.1351770
3    R  5 -0.6693774  0.09059365 -2.5297829  0.3233827 -0.9383348 -0.4461412  1.281797  1.5315622  1.4897071 -0.4461412
4    B  4 -0.4461412 -0.93833476 -1.2443708 -0.4461412 -0.1894970 -0.9383348 -1.135177 -1.8991102 -0.1894970  0.4026905
5    K  2 -1.0180271 -1.06509624 -0.1939600 -0.1894970  1.4897071 -0.6693774 -1.899110 -1.3197276  1.5315622 -0.1517500
6    Y  3  1.5315622 -0.19396005 -0.4917057 -0.4664239 -1.8991102  0.4026905 -1.065096 -0.9383348 -1.2443708 -0.4664239

谢谢


在您的例子中,P1-P10 是因子。它们在您的数据集中也是这样吗? - ECII
是的,它们是我的数据集中的因素,抱歉我回复晚了。 - user2380782
好的,我的答案现在可以处理因子和字符。 - ECII
2个回答

3
您可以在 df1[[1]] 中匹配 df2[3:12] 的值。使用这些行号从 df1[2] 中提取值。
df2[3:12] <- df1[match(as.character(unlist(df2[3:12])), 
                       as.character(df1[[1]])), 2]

结果(df2):
  Name bd         P1         P2         P3         P4         P5         P6         P7         P8         P9        P10
1    H  5  0.1199355  0.3752010 -0.3926061 -1.1039548 -0.1107821  0.9867373 -0.3360094 -0.7488000 -0.3926061  2.0667704
2    U  4  0.1168599  0.1168599  0.9867373  1.3521418  0.9867373 -0.3360094 -0.7724007 -0.3926061 -0.3360094 -1.2543480
3    R  3 -1.2337890 -0.1107821 -0.7724007  2.0667704  0.3752010  0.4645504  0.9867373  0.1168599 -0.0981773 -0.3926061
4    G  2 -0.3926061  0.3199261 -0.0981773 -0.1107821  2.0667704 -1.1039548 -1.2337890  0.3199261 -1.2337890 -2.1534678
5    C  6 -2.1534678 -1.1039548 -1.1039548 -0.7488000  0.4645504  0.3199261 -2.1534678 -0.3360094  0.9867373  0.8771467
6    I  1  0.6171634  0.6224091  1.8011711  0.7292998  0.8771467  2.0667704  0.3752010  0.4645504 -2.1534678 -0.7724007

如果您不想替换df2中的值,可以创建一个新的数据框df4,并使用以下内容:
df4 <- "[<-"(df2, 3:12, value = df1[match(as.character(unlist(df2[3:12])), 
                                          as.character(df1[[1]])), 2])

@user2380782 在我的代码中,3:12表示我们感兴趣的列数。也许你应该尝试换成3:10000 - Sven Hohenstein
是的,我做了。有点奇怪...我会尝试弄清楚发生了什么。 - user2380782
你好@Sven Hohenstein,问题在于当我将 data.frame 转换为 matrix 时,我忘记了结构是不同的。因此,我应该添加 df1[match(as.character(unlist(df2[,3:12])。一个逗号可以产生很大的差异... - user2380782
你能告诉我如何创建一个新的 matrix,而不是像你为 df4 <- "[<-"(df2, ... 中的 data.frame 那样吗?非常感谢。 - user2380782
@user2380782 只需创建数据框,然后使用 as.matrix(df4) - Sven Hohenstein
显示剩余5条评论

0

尝试一些*pply魔法:

lookup<-tapply(df1$V2, df1$V1, unique) #Creates a lookup table
lookup.function<-function(x) as.numeric(lookup[as.character(x)]) #The function
df4<-data.frame(df2[,1:2], apply(df2[,3:12], 2,lookup.function )) #Builds the output

更新:

*pply系列比merge快得多,至少快一个数量级。看看这个。

num<-1000
df1 = data.frame(V1=LETTERS, V2=rnorm(26))
df2<-data.frame(cbind(first=1:num,second=1:num, matrix(sample(LETTERS, num^2, replace=T), nrow=num, ncol=num)))


start<-Sys.time()
lookup<-tapply(df1$V2, df1$V1, unique)
lookup.function<-function(x) as.numeric(lookup[as.character(x)])
df4<-data.frame(cbind(df2[,1:2], data.frame(apply(df2[,3:(num+2)], 2, lookup.function ))))
(difftime(Sys.time(),start))


start<-Sys.time()
df4.merge <- "[<-"(df2, 3:num, value = df1[match(as.character(unlist(df2[3:num])), as.character(df1[[1]])), 2])
(difftime(Sys.time(),start))

sum(df4==df4.merge)==num^2

对于3000列和行,*pply组合需要4.3秒,而merge在我的缓慢英特尔上需要约22秒。它的扩展性很好。对于4000列和行,相应的时间分别为7.4秒和118秒。

如果我将这些数据框转换为矩阵类以加快计算速度,那么我是否可以采用您的方法来匹配单个数据框?谢谢@ECII - user2380782
为什么你要进行转换?我的方法有什么问题吗?你必须给我们提供可重现的示例。 - ECII
我已经将data.frame转换为矩阵,因为它来自于我的数据框列表中的采样步骤,而在使用lapply进行迭代时,数据框比矩阵慢。我没有发布包括数据框列表的问题,因为我认为将数据框列表总结成一个数据框会更容易理解,但这是一个错误。但是你的方法没有问题,只是想问一下是否可以在矩阵上实现它。感谢您的快速回复。 - user2380782
1
你说你有6行和10,000列的数据框。我的答案只需要不到一秒钟就能匹配。你还需要什么? - ECII
嗨@ECII,你的方法真的很快,而且效果非常好。然而,我正在尝试将其应用于在一个矩阵列表中运行数据框,但是这需要很长时间,可能是因为lapply?谢谢。 - user2380782
我想这应该可以修改一下,让它能够处理列表和矩阵。 - ECII

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接