使用 apply() 和 ifelse() 语句逐列比较 2 data.frames 以根据比较报告 1 或 0

问题描述 投票:0回答:1

我的目标有两个:

  1. 逐列比较 2 个数据帧(df1,df2)。如果任何比较在任一单元格(df1 或 df2)中具有“无”,则报告 0。如果比较中不存在“无”,则报告 1。此循环的结果将是中间步骤(请参见下面的流程图)。

  2. 总结所有结果的最终数据框(按列和行)。此 data.frame 中的总列将等于 df1 中的总列(df1 的列名),并且此 data.frame 的总行将包含(作为 row.names)df2 中的列以及每个单元格中的总和(例如 C1-M1、C2-M2 等的比较)。请参阅下面流程图中的#3。

我整理了一个视觉效果:使用 df1、df2 的流程图,以便您可以看到我的目标是什么以及我的最终数据框架的目标是什么:

制作 df1 和 df2 的代码

df1 <- data.frame(C1 = c("A", "B", "None"), C2 = c("B", "A", "A"),  
              C3 = c("None", "None", "B"), row.names = paste0("Proj.", 1:3))
df2 <- data.frame(M1 = c("A", "None", "B"), M2 = c("B", "None", "B"),  
              M3 = c("A", "B", "B"), M4 = c("None", "None", "None"),  row.names = paste0("Proj.", 1:3)) 

我已经搜索了关于如何完成目标 1 的代码,并且发现相当多的帖子在 R 的

ifelse
函数中组合了一个
apply
,所以我从一个
ifelse
语句开始,但这确实没有考虑如何包含“无”以将其变成 0,所以结果是错误的(但到达那里):

ifelse(df1$C1 == df2[, c("M1", "M2", "M3", "M4")], 1, 0)
    M1 M2 M3 M4
Proj.1  1  0  1  0
Proj.2  0  0  1  0
Proj.3  0  0  0  1

This loop comes close,但我不知道

apply
是如何循环的。它不是 C1-M1、C1-M2、C1-M3 组合,也不是 C1-M1、C2-M1、C3-M1 等。此外,这不会将“无”更改为 0。

t(apply(df1, 1, function(x) ifelse(x == df2, 1, 0)))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
Proj.1    1    0    0    0    0    0    1    1    0     0     0     1
Proj.2    0    0    0    1    0    0    0    0    0     0     0     1
Proj.3    0    0    1    0    0    1    0    0    1     1     0     0

我从这个特定链接中获得灵感R: ifelse statement: comparing data.frames 在比较 2 个 data.frames 的同时在

ifelse
语句中寻找字符。我将 df1、df2 中的所有“无”更改为数字 0 并再次尝试,但这给了我一个错误。

df1.1 <- as.data.frame(t(unlist(apply(df1, 1, function(x) ifelse(x == "None", 0, x)))))
df2.2 <- as.data.frame(t(unlist(apply(df2, 1, function(x) ifelse(x == "None", 0, x)))))
apply(df1.1, 1, function(x) ifelse(x == as.numeric(df2.2, 0, 1)))

ifelse(x == as.numeric(df2.2, 0, 1)) 中的错误:无法强制“列表”对象键入“double”

我想知道我做错了什么?任何帮助是极大的赞赏。谢谢你。

r dataframe loops if-statement apply
1个回答
0
投票

数据的结构方式实际上是矩阵/数组,而不是 data.frames,所以这里有一个矩阵解决方案:

首先制作数据矩阵并为

NA
字符串插入
"None"
s:

df1 <- data.frame(C1 = c("A", "B", "None"), C2 = c("B", "A", "A"),  
                  C3 = c("None", "None", "B"), row.names = paste0("Proj.", 1:3))
df2 <- data.frame(M1 = c("A", "None", "B"), M2 = c("B", "None", "B"),  
                  M3 = c("A", "B", "B"), M4 = c("None", "None", "None"),  row.names = paste0("Proj.", 1:3))

m1 <- as.matrix(df1)
m2 <- as.matrix(df2)
m1[m1 == "None"] <- NA
m2[m2 == "None"] <- NA

m1
#>        C1  C2  C3 
#> Proj.1 "A" "B" NA 
#> Proj.2 "B" "A" NA 
#> Proj.3 NA  "A" "B"
m2
#>        M1  M2  M3  M4
#> Proj.1 "A" "B" "A" NA
#> Proj.2 NA  NA  "B" NA
#> Proj.3 "B" "B" "B" NA

然后遍历

proj
值,检查它们在哪里不是
NA
,为每个 C/M 组合创建一个矩阵,并在项目维度上聚合:

rownames(m1) |>
    # use sapply to keep names, but don't simplify
    sapply(
        # make a matrix for corresponding proj rows of m1 and m2
        function(i) outer(!is.na(m1[i, ]), !is.na(m2[i, ]), FUN = `*`), 
        simplify = FALSE
    ) |>
    simplify2array() |>
    # sum over the third (proj) dimension of the array
    apply(2:1, sum)
#>    C1 C2 C3
#> M1  1  2  1
#> M2  1  2  1
#> M3  2  3  1
#> M4  0  0  0

你也可以用 data.frames 解决这个问题,但是这样做的话,把你的数据放在长格式中会更容易。

© www.soinside.com 2019 - 2024. All rights reserved.