【问题标题】:Compare multiple boolean columns in r比较 r 中的多个布尔列
【发布时间】:2018-11-21 04:32:12
【问题描述】:

小填字游戏。和往常一样,我认为我错过了一些东西。我有一个这样的数据框:

id creator att1 att2 att3 att... att500
a1 person1 TRUE TRUE FALSE ...
a2 person2 TRUE TRUE TRUE ...
a3 person1 TRUE FALSE FALSE ...
a4 person1 TRUE TRUE FALSE ...
a5 person2 TRUE TRUE FALSE ...

等等。我想计算不同创建者对相同属性组合(大约 500 个布尔值)的出现次数,并对每一行执行此操作,并将计数添加到相应的行中。因此,在上面的示例中,我希望第一行 (a1) 的 count=1,因为在 a5 中,不同的人已经完成了完全相同的属性组合。请注意,a4 不算数,因为它是相同的组合但由同一个人组成。想想自己混合的鸡尾酒,以及它们由彼此独立的不同人混合的频率。行 a2 的计数应为 0,因此 a3(没有相同的属性组合)和 a4 应分别计数 = 1,因为 a5。 a5 的计数也为 1。但是,如果其他人多次混合相同的鸡尾酒,则应计算在内。我不想简单地删除重复项。

因此,我的计划是遍历行,排除同一行创建者的所有鸡尾酒,获取属性组合并将其与临时数据集中的所有行进行比较:

for (row in 1:nrow(data)){ 
# for each row in data
   creator <- row$creator 
# get creator
   attr_tupel <- row[1, 3:500] 
#return the attribute combination of the row
   data[row]$count <- nrow(data[data$creator != creator & data[3:500] == attr_tupel]) 
# into the column $count of the current row write the number of observations that are not from the same creator and match the exact tupel of my ~500 Attributes (equal cocktails by different persons)
}

不幸的是,我无法将参考行的元组与其他行进行比较,因为 '==' 只为同样大小的数据帧定义

现在我被困住了。我可以肯定地单独写每一列——但这需要很长时间。我是否需要将该数据框转换为列表或向量或 //在此处插入 sthg//(向量和列表不起作用。)是否有可能将一行值与许多值进行比较其他行是否相等?我不认为拥有该行的副本将是解决方案,除了通常 R 在他没有任何可比较的内容时会简单地遍历条目。为什么不在这里?

我阅读了几个关于相互比较几列的主题,但没有成功地将解决方案转移到我的问题上。例如:wants to look up one value for the boolish value, I have multiple TRUE values, same,wants to convert to a c() - which I could do too and compare those, but kind of a hard way, isn't it?

最后(来自最后一个链接)我现在什至在考虑将布尔值转换为数字(添加索引以便我们拥有

id creator att1 ... index
a1 person1 1 2 0 ... 3 
a2 person2 1 2 3 ... 6

并比较该索引。应该管用。但是感觉这是一个丑陋的解决方法。此外,当考虑使用布尔值以外的数据时,比如几个字符串,从长远来看,我仍然希望能够独立于它们的内容来比较一个元组列。

我错过了什么? :)

感谢您的帮助!

按照评论中的要求,这里是创建类似数据框的简短脚本。请记住,还有更多列可供比较。

id <- 1:50
names <- paste("creator", rep(1:10, each = 5))
bools1 <- rnorm(n=50, mean = 5, sd = 3)
bools1 <- ifelse(bools1>5, TRUE, FALSE)
bools2 <- rnorm(n=50, mean = 5, sd = 3)
bools2 <- ifelse(bools2>5, TRUE, FALSE)
bools3 <- rnorm(n=50, mean = 5, sd = 3)
bools3 <- ifelse(bools3>5, TRUE, FALSE)
bools4 <- rnorm(n=50, mean = 5, sd = 3)
bools4 <- ifelse(bools4>5, TRUE, FALSE)
bools5 <- rnorm(n=50, mean = 5, sd = 3)
bools5 <- ifelse(bools5>5, TRUE, FALSE)

data <- data.frame(id, names, bools1, bools2, bools3, bools4, bools5)

【问题讨论】:

  • 嗨阿克伦,谢谢!你可以在那里剪掉它。它只是注意到像这样的解决方案 nrow(data[data$att1 == row$att1 & data$att2 == row att2 & data$att3 == row$att3]) 是不切实际的。这个问题尤其会随着大约 500 列中不同组合的大小而演变。
  • @akrun 上面我添加了一些代码来创建示例数据框。谢谢!
  • 类似m1 &lt;- combn(names(data)[-(1:2)], 2, FUN = function(x) rowSums(data[x])); colnames(m1) &lt;- combn(names(data)[-(1:2)], 2, FUN = paste, collapse="_")

标签: r loops boolean comparison


【解决方案1】:

编辑:抱歉 - 我的第一个解决方案误读了问题。试试这个

您可以使用数据表运行它:

#Your set up data (with seed)
set.seed(123)
id <- 1:50
names <- paste("creator", rep(1:10, each = 5))
bools1 <- rnorm(n=50, mean = 5, sd = 3)
bools1 <- ifelse(bools1>5, TRUE, FALSE)
bools2 <- rnorm(n=50, mean = 5, sd = 3)
bools2 <- ifelse(bools2>5, TRUE, FALSE)
bools3 <- rnorm(n=50, mean = 5, sd = 3)
bools3 <- ifelse(bools3>5, TRUE, FALSE)
bools4 <- rnorm(n=50, mean = 5, sd = 3)
bools4 <- ifelse(bools4>5, TRUE, FALSE)
bools5 <- rnorm(n=50, mean = 5, sd = 3)
bools5 <- ifelse(bools5>5, TRUE, FALSE)

data <- data.frame(id, names, bools1, bools2, bools3, bools4, bools5)

# Code to run

library(data.table)

setDT(data)
dt_m <- melt(data, id.vars = c("id","names"), variable.factor = TRUE)
dt_m <- dt_m[,.(drink = paste0(value, collapse = "_")), by = .(id, names)]
dt_m[, times_made := .N, by = drink][, times_made_others := times_made - .N, by = .(drink, names)]
dt_out <- merge(data, dt_m[, .(id, drink, times_made_others)], by = "id")

本质上,您所做的是通过将列折叠在一起来创建“饮料”,计算其他人制作饮料的次数,然后将其合并回您的原始数据集。

dt_out
    id      names bools1 bools2 bools3 bools4 bools5                        drink times_made_others
 1:  1  creator 1  FALSE   TRUE  FALSE   TRUE   TRUE   FALSE_TRUE_FALSE_TRUE_TRUE                 3
 2:  2  creator 1  FALSE  FALSE   TRUE   TRUE   TRUE   FALSE_FALSE_TRUE_TRUE_TRUE                 1
 3:  3  creator 1   TRUE  FALSE  FALSE   TRUE  FALSE  TRUE_FALSE_FALSE_TRUE_FALSE                 2
 4:  4  creator 1   TRUE   TRUE  FALSE  FALSE   TRUE   TRUE_TRUE_FALSE_FALSE_TRUE                 0
 5:  5  creator 1   TRUE  FALSE  FALSE  FALSE  FALSE TRUE_FALSE_FALSE_FALSE_FALSE                 3
 6:  6  creator 2   TRUE   TRUE  FALSE  FALSE  FALSE  TRUE_TRUE_FALSE_FALSE_FALSE                 2
 7:  7  creator 2   TRUE  FALSE  FALSE   TRUE  FALSE  TRUE_FALSE_FALSE_TRUE_FALSE                 2

【讨论】:

  • 太棒了。太感谢了。我之前也尝试过使用数据表函数和 .N 来解决它,但由于某种原因没有成功。从未尝试使用两个分组变量进行分组,并且以某种方式覆盖了每个新行中的旧值。是那么的简洁明了!以前从未使用过 melt() ,将读入它。通常需要一些时间来消化您的代码,但我将其调整为大型数据集,检查了一些案例,它看起来完美无瑕。顺便说一句,以这种方式折叠“食谱”的好主意!这不仅在这里而且在路上都会非常有帮助!再次感谢!
  • 旁注:现在收据/多列减少到一列,也可以轻松地循环遍历行和计数。以防万一有人需要: for (row in 1:nrow(data)){ data$count[row]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-21
  • 2017-07-27
  • 2020-11-23
  • 2019-05-28
  • 2012-08-19
  • 2017-02-07
相关资源
最近更新 更多