【问题标题】:R: How to identify unknown number of combinations?R:如何识别未知数量的组合?
【发布时间】:2020-04-16 20:29:28
【问题描述】:

我有以下格式的数据:

Data <- data.frame(
  Names = c("Person A", "Person B","Person F", "Person G", "Person F", "Person G", "Person Q", "Person R"),
  Time_Stamp = c("2013-08-01 07:06:00", "2013-08-01 07:06:00", "2013-08-01 07:53:00", "2013-08-01 07:53:00", "2013-08-01 11:01:00", "2013-08-01 11:01:00", "2013-08-01 11:08:00", "2013-08-19 06:57:00")
)

#> Data
#      Names          Time_Stamp
# 1 Person A 2013-08-01 07:06:00
# 2 Person B 2013-08-01 07:06:00
# 3 Person F 2013-08-01 07:53:00
# 4 Person G 2013-08-01 07:53:00
# 5 Person F 2013-08-01 11:01:00
# 6 Person G 2013-08-01 11:01:00
# 7 Person Q 2013-08-01 11:08:00
# 8 Person R 2013-08-19 06:57:00

我想创建一个代码,用于识别何时出现人员组合(顺序无关紧要)并带有相同的时间戳。因此,例如,人物 F 和人物 G 同时出现在 2013 年 8 月 1 日的 8 点 14 分,所以他们是一个组,并获得一个唯一的组名。如果他们再次一起出现,他们仍然会得到相同的名字。我一直遇到的问题是,真实数据接近 100,000 行,我不知道其中有多少人组合出现了相同的时间戳,并且组合可能不止 2 个人。

我希望新数据看起来像这样:

Desired <- data.frame(
  Names = c("Person A", "Person B","Person F", "Person G", "Person F", "Person G", "Person Q", "Person R"),
  Time_Stamp = c("2013-08-01 07:06:00", "2013-08-01 07:06:00", "2013-08-01 07:53:00", "2013-08-01 07:53:00", "2013-08-01 11:01:00", "2013-08-01 11:01:00", "2013-08-01 11:08:00", "2013-08-19 06:57:00"),
  Group = c("Group 1", "Group 1", "Group 2", "Group 2", "Group 2", "Group 2", "No Group", "No Group")
)
#      Names          Time_Stamp    Group
# 1 Person A 2013-08-01 07:06:00  Group 1
# 2 Person B 2013-08-01 07:06:00  Group 1
# 3 Person F 2013-08-01 07:53:00  Group 2
# 4 Person G 2013-08-01 07:53:00  Group 2
# 5 Person F 2013-08-01 11:01:00  Group 2
# 6 Person G 2013-08-01 11:01:00  Group 2
# 7 Person Q 2013-08-01 11:08:00 No Group
# 8 Person R 2013-08-19 06:57:00 No Group

【问题讨论】:

  • 谢谢,这样好些了吗?
  • Person Q 和 R 属于同一个"No Group"?
  • 是的,然后我就放弃它们。我只对成组出现的人感兴趣,而不是单独出现。

标签: r combinations identification


【解决方案1】:

我相信以下功能可以满足问题的要求。

代码工作如下:

  1. 因子在内部被编码为连续的整数,因此强制转换为因子,然后转换为整数,以便将每个唯一的 "Time_Stamp" 视为字符串,以获得唯一的整数。
  2. 使用ave 将整数向量除以"Names",如果f 跨越多个名称,则只保留第一个。
  3. 最后,如果f的每一层只有一个元素,则返回"No Group",否则在该层之前粘贴"Group"

此函数仅使用基数 R,但可以在 dplyr::mutate 指令中使用。

group_names <- function(x, col.name, col.date){
  f <- as.integer(as.factor(x[[col.date]]))
  f <- ave(f, x[[col.name]], FUN = function(x){
    if(length(x) > 1) x[1] else x
  })
  f <- ave(f, f, FUN = function(x){
    if(length(x) == 1) "No Group" else paste("Group", x)
  })
  f
}

Data$Group <- group_names(Data, "Names", "Time_Stamp")

或者,dplyr。列号或列名都有效。

Data %>% mutate(Group = group_names(., 1, 2))
Data %>% mutate(Group = group_names(., "Names", "Time_Stamp"))
#     Names          Time_Stamp    Group
#1 Person A 2013-08-01 07:06:00  Group 1
#2 Person B 2013-08-01 07:06:00  Group 1
#3 Person F 2013-08-01 07:53:00  Group 2
#4 Person G 2013-08-01 07:53:00  Group 2
#5 Person F 2013-08-01 11:01:00  Group 2
#6 Person G 2013-08-01 11:01:00  Group 2
#7 Person Q 2013-08-01 11:08:00 No Group
#8 Person R 2013-08-19 06:57:00 No Group

【讨论】:

  • 非常感谢!第一个对我来说效果很好!
  • 您好!你能解释一下答案第一部分的代码吗?
  • 谢谢!我现在注意到我以前没有考虑过的真实数据。如果有一组 5 个人在同一天都有相同的时间戳,说它是(A 人、B 人、C 人、D 人和 E 人),并且在该组中出现了较小的组5,说(人 A 和人 B)在新的一天有相同的时间戳,(人 A 和人 E)在另一天有相同的时间戳,他们仍然被标记为第 1 组,但我想要这些较小的组中的每一个都被标记为单独的组。你知道我会怎么做吗?我被难住了。
【解决方案2】:

这是使用igraph的解决方案

library(igraph)
u <- graph_from_data_frame(Data)
grp <- clusters(u)$membership[match(Data$Names,names(clusters(u)$membership))]
Desired <- within(Data, Group <- ave(grp,grp,FUN = function(x) {if (length(x)>1) paste("Group",x) else "No Group"}))

这样

> Desired
     Names          Time_Stamp    Group
1 Person A 2013-08-01 07:06:00  Group 1
2 Person B 2013-08-01 07:06:00  Group 1
3 Person F 2013-08-01 07:53:00  Group 2
4 Person G 2013-08-01 07:53:00  Group 2
5 Person F 2013-08-01 11:01:00  Group 2
6 Person G 2013-08-01 11:01:00  Group 2
7 Person Q 2013-08-01 11:08:00 No Group
8 Person R 2013-08-19 06:57:00 No Group

【讨论】:

  • 感谢您的回答!所以这个,我在我的真实数据上进行了测试,它接近我需要的,但它只是根据组的第一次出现按数字顺序创建组名称。因此,如果一个组多次出现,该组的下一次出现将获得一个新名称。第一个答案虽然做了我需要做的事情,所以不用担心。再次感谢!
  • @ellie9813 感谢您的反馈。我更新了使用igraph 进行聚类和标记的解决方案。也许你可以看看。
【解决方案3】:

使用data.table的选项:

library(data.table)
setDT(Data, key=c("Time_Stamp","Names"))
Data[, g := if (.N > 1L) paste(Names, collapse=""), Time_Stamp]
Data[order(g), g := fifelse(is.na(g), NA_integer_, rleid(g))]

输出:

      Names          Time_Stamp    g
1: Person A 2013-08-01 07:06:00    1
2: Person B 2013-08-01 07:06:00    1
3: Person F 2013-08-01 07:53:00    2
4: Person G 2013-08-01 07:53:00    2
5: Person F 2013-08-01 11:01:00    2
6: Person G 2013-08-01 11:01:00    2
7: Person Q 2013-08-01 11:08:00 <NA>
8: Person R 2013-08-19 06:57:00 <NA>

【讨论】:

  • 感谢您的回答!我在我的实际数据上试过这个,但由于某种原因,没有人被分配 NA。能否请您解释一下代码,我可以看看是否有我遗漏的东西?
  • 您可以尝试将记录添加到数据集的顶部,例如data.table(Names="ajdijoeqnwfnwd", Time_Stamp="aksjdlakjds"),如果这不是 NA,那么代码确实有问题。我还对数据集进行了排序,因为名称可能未排序。
猜你喜欢
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-03
  • 2015-04-18
  • 2014-07-05
  • 2012-12-28
相关资源
最近更新 更多