【问题标题】:replace some column values from a data.frame based on another data.frame根据另一个 data.frame 替换 data.frame 中的某些列值
【发布时间】:2013-12-11 19:42:24
【问题描述】:

我有两个 data.frames,(df1, df2),我想将 P1-P10 列中的值替换为 df1$V2 的值,但保留 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 是因子。在你的数据集中真的是这样吗?
  • 是的,它们是我数据集中的因素,抱歉我回复晚了
  • 好的,我的答案现在适用于因子和字符。

标签: r


【解决方案1】:

您可以在df1[[1]]match 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])

【讨论】:

  • 你好@Sven Hohensein,我的数据发生了一些奇怪的事情,我已将我的 data.frame 转换为矩阵以加快计算速度(7 行,10,000 列)。当我应用您的解决方案时,仅在一定数量的列之前替换值,例如,从 1220 开始,值不会被替换,保持“字符”值。我的数据输入太大,无法在此处发布,但我想寻求您的帮助。非常感谢
  • @user2380782 在我的代码中,3:12 表示感兴趣的列数。也许你应该改用3:10000
  • @user2380782 是否将3:12 都替换为3:dim(df)[2]
  • 是的,我做到了。这有点奇怪......我会试着弄清楚发生了什么
  • 你好@Sven Hohenstein,问题是当我将data.frame 转换为matrix 时,我忘记了结构不同,所以我应该添加df1[match(as.character(unlist(df2[,3:12]), 有很大的不同...
【解决方案2】:

试试*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 秒。

【讨论】:

  • 如果我将 data.frames(现在我有一个我想与单个 data.frame 匹配的 data.frames 列表)转换为矩阵类以加速计算,我可以适应吗你的方法?谢谢@ECII
  • 为什么要转换任何东西?我的方法有什么问题?你必须给我们可重复的例子
  • 我已将 data.frame 转换为矩阵,因为它来自上一个步骤,涉及在我的 data.frames 列表中进行采样,并且与矩阵相比,使用 lapply 的每次迭代在 data.frames 中都很慢。我没有发布我的问题,包括 data.frames 列表,因为我认为将 data.frames 列表汇总到 data.frame 中会更容易理解,但这是一个错误。但是你的方法没有错,只是问我是否可以在矩阵上实现它。感谢您的快速回复
  • 您说您有 6 行 10.000 列的数据框。我的答案应该用不到一秒钟的时间来匹配。你还需要什么?
  • 嗨@ECII,您的方法非常快,而且效果非常好。但是我正在尝试将它应用于在一个列表中运行一个针对 data.frame 的矩阵并且它需要很长时间,可能是因为lapply?谢谢
猜你喜欢
  • 1970-01-01
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-15
  • 1970-01-01
相关资源
最近更新 更多