【问题标题】:Extracting first column that meets certain criteria for each row提取满足每行特定条件的第一列
【发布时间】:2016-10-11 21:47:30
【问题描述】:

我会尽力解释我在做什么,这有点令人困惑,但我会试一试。基本上我从 2 个数据帧开始。每个包含每个人唯一的行和每个用户两个项目作为列。我的目标是将其转换为 1 个数据框,每个用户有一个唯一行,并且在项目不重复的情况下,这两个数据框中的第一个项目。例如,如果对于第一个数据框中的客户 1,他的项目是“a”和“d”,而在第二个数据框中,他的项目是“a”和“c”,我希望最终数据框是“a”和“c”代表这个客户。我已经编写了一个应用程序来执行此操作,但是当我在大约 160,000 行上执行此操作时,它需要相当多的时间。我希望有人能够为我的问题提出更有效的解决方案。

d1 <- data.frame(id = c("1", "2", "3"), stringsAsFactors = F)
r1 <- data.frame(i1 = c("a", "b", "c"), i2 = c("d", "e", "f"), stringsAsFactors = F)
rownames(r1) = d1$id
r2 <- data.frame(i1 = c("a", "c", "f"), i2 = c("c", "t", "l"), stringsAsFactors = F)
rownames(r2) = d1$id

dFinal <- data.frame(id = d1$id, r1 = "", r2 = "", stringsAsFactors = F)

dFinal$r1 = apply(dFinal, 1, function(x){r1[rownames(r1) == x["id"], "i1"]})
dFinal$r2 = apply(dFinal, 1, function(x){r2[rownames(r2) == x["id"], which(!r2[rownames(r2) == x["id"],c("i1","i2")] %in% x["r1"])[1]]})

【问题讨论】:

  • 嗯,我可以看到合并工作,但是我不确定合并的一个部分是如何在合并后选择正确的列。假设 r1 和 r2 将 id 作为列而不是行名。 dInter &lt;- merge(r1,r2, by = "id") 但是我不知道如何从只选择正确列的应用中复制逻辑
  • 在你的例子中,为什么是 ac 而不是 ad?还有其他标准吗?
  • @Parfait 我想从每个数据帧中取出前一个数据帧中不存在的第一个可用列。因此,从第一个数据框中选择第一列 a 然后对于第二个数据框中的相同 id 选择 ac,由于 a 已用于第一个数据帧,因此选择 c

标签: r for-loop apply


【解决方案1】:

以下内容是否符合您的要求:

# Keep only first column of first data.frame
df <- cbind(d1,r1,r2)[,-3]
names(df) <- c("id","r1_final","r2_i1","r2_i2")
df$r2_final <- df$r2_i1

# Keep only second column of second data.frame
# if the value in the first column is found in first data.frame
df[df$r1_final == df$r2_i1,"r2_final"] <- df[df$r1_final == df$r2_i1,"r2_i2"]
df_final <- df[,c("id","r1_final","r2_final")]
print(df_final)

  id r1_final r2_final
1  1        a        c
2  2        b        c
3  3        c        f

编辑: 如果有四个 data.frames 而不是示例中的 2 个,OP 要求提供解决方案,这里有一些我没有测试过的代码,但它应该与另外两个列一起使用

df$r2_final <- df$r2_i1
df$r3_final <- df$r3_i1
df$r4_final <- df$r4_i1

df[df$r1_final == df$r2_i1,"r2_final"] <- df[df$r1_final == df$r2_i1,"r2_i2"]
df[df$r3_i1 %in% c(df$r1_final,df$r2_final),"r3_final"] <- df[df$r3_i1 %in% c(df$r1_final,df$r2_final),"r3_i2"]
df[df$r4_i1 %in% c(df$r1_final,df$r2_final,df$r3_final),"r4_final"] <- df[df$r4_i1 %in% c(df$r1_final,df$r2_final,df$r3_final),"r4_i2"]
df_final <- df[,c("id","r1_final","r2_final","r3_final","r4_final")]

【讨论】:

  • 这可能是个好主意!仅编辑重复值的行。我确实认为这解决了我发布的问题,但如果你不介意我问的话,我有一个跟进。在实际问题中,我试图填写 4 个 r_final 列。我猜如果我只是扩展你的答案,这会起作用,但我不确定如果说我不希望 r3_final 会是什么样子等于 r1_final 和 r2_final。
  • 我添加了一个编辑,如果您有更多或可变数量的 data.frames 可以使用,那么我会编写一个函数,您可以在每个列数上使用。我可以想象使用一个循环遍历不同的 data.frames / 列的循环。如果您有很多行,请不要循环/应用这些行,这会使代码变慢。
【解决方案2】:

感谢您接受的答案,因为它运行良好!然而,它给了我一个使用 ifelse 的想法。虽然它没有比公认的答案更好或更差,但在添加更多列或数据框时,我更容易绕开我的脑袋。

  dfInt <- cbind(df1, df2, df3, df4)
  dfInt$R1_Final <- dfInt$R1_1
  dfInt$R2_Final <- ifelse(dfInt$R1_Final == dfInt$R2_1,
                               dfInt$R2_2,
                               dfInt$R2_1)
  dfInt$R3_Final <- ifelse(dfInt$R1_Final != dfInt$R3_1 & dfInt$R2_Final != dfInt$R3_1,
                               dfInt$R3_1,
                               ifelse(dfInt$R2_Final != dfInt$R3_2,
                                      dfInt$R3_2,
                                      dfInt$R3_3))
  dfInt$R4_Final <- ifelse(dfInt$R1_Final != dfInt$R4_1 & dfInt$R2_Final != dfInt$R4_1 & dfInt$R3_Final != dfInt$R4_1,
                               dfInt$R4_1,
                               ifelse(dfInt$R2_Final != dfInt$R4_2 & dfInt$R3_Final != dfInt$R4_2,
                                      dfInt$R4_2,
                                      ifelse(dfInt$R3_Final != dfInt$R4_3,
                                             dfInt$R4_3,
                                             dfInt$R4_4)))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-22
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多