在R中识别重复/唯一的团队(和重组数据)

时间:2015-01-05 21:52:02

标签: r

我有一个如下所示的数据集:

 Person Team
   1     30
   2     30
   3     30
   4     30
   11    40
   22    40
   1     50
   2     50
   3     50
   4     50
   15    60
   16    60
   17    60
   1     70
   2     70
   3     70
   4     70
   11    80
   22    80

我的总体目标是组织团队识别码,以便轻松查看哪些团队彼此重复以及哪些团队是唯一的。我想总结数据,看起来像这样:

 Team   Duplicate1  Duplicate2
  30        50          70
  40        80  
  60        

如您所见,团队30,50和70拥有相同的成员,因此他们共享一行。同样,团队40和80拥有相同的成员,因此他们共享一行。只有60队(在本例中)才是唯一的。

在团队重复的情况下,我不关心哪个团队ID在哪个列中。此外,团队可能有两个以上的重复。团队规模从2名成员到8名成员。

5 个答案:

答案 0 :(得分:3)

此答案提供您要求的输出数据格式。我将重复的团队留在一个变量中,因为我认为这是处理任意数量的重复项的更好方法。

require(dplyr)

df %>%
  arrange(Team, Person) %>%   # this line is necessary in case the rest of your data isn't sorted
  group_by(Team) %>%
  summarize(players = paste0(Person, collapse = ",")) %>%
  group_by(players) %>%
  summarize(teams = paste0(Team, collapse = ",")) %>%
  mutate(
    original_team = ifelse(grepl(",", teams), substr(teams, 1, gregexpr(",", teams)[[1]][1]-1), teams),
    dup_teams = ifelse(grepl(",", teams), substr(teams, gregexpr(",", teams)[[1]][1]+1, nchar(teams)), NA)
  )

结果:

Source: local data frame [3 x 4]

   players    teams original_team dup_teams
1  1,2,3,4 30,50,70            30     50,70
2    11,22    40,80            40        80
3 15,16,17       60            60        NA

答案 1 :(得分:2)

将此用作样本数据

dd<-structure(list(Person = c(1L, 2L, 3L, 4L, 11L, 22L, 1L, 2L, 3L, 
4L, 15L, 16L, 17L, 1L, 2L, 3L, 4L, 11L, 22L), Team = c(30L, 30L, 
30L, 30L, 40L, 40L, 50L, 50L, 50L, 50L, 60L, 60L, 60L, 70L, 70L, 
70L, 70L, 80L, 80L)), .Names = c("Person", "Team"), 
class = "data.frame", row.names = c(NA, -19L))

您可以尝试使用table()/ interaction()来查找重复的组。例如

tt <- with(dd, table(Team, Person))
grp <- do.call("interaction", c(data.frame(unclass(tt)), drop=TRUE))
split(rownames(tt), grp)

返回

$`1.1.1.1.0.0.0.0.0`
[1] "30" "50" "70"

$`0.0.0.0.0.1.1.1.0`
[1] "60"

$`0.0.0.0.1.0.0.0.1`
[1] "40" "80"

所以小组&#34;名字&#34;实际上只是每个人的会员指标。如果您愿意,可以使用setNames()轻松地重命名它们。但是在这里它会使相应的团队崩溃。

答案 2 :(得分:2)

不完全是您想要的格式,但非常有用:

# using MrFlick's data
library(dplyr)
dd %>% group_by(Team) %>%
    arrange(Person) %>%
    summarize(team.char = paste(Person, collapse = "_")) %>%
    group_by(team.char) %>%
    arrange(team.char, Team) %>%
    mutate(duplicate = 1:n())

Source: local data frame [6 x 3]
Groups: team.char

  Team team.char duplicate
1   40     11_22         1
2   80     11_22         2
3   60  15_16_17         1
4   30   1_2_3_4         1
5   50   1_2_3_4         2
6   70   1_2_3_4         3

(如果数据尚未排序,则在arrange(Person)行编辑,从@Reed的回答中得到了想法。)

答案 3 :(得分:2)

另外两个基本R选项(尽管不完全是所需的输出):

DF2 <- aggregate(Person ~ Team, DF, toString)
> split(DF2$Team, DF2$Person)
$`1, 2, 3, 4`
[1] 30 50 70

$`11, 22`
[1] 40 80

$`15, 16, 17`
[1] 60

或者

( DF2$DupeGroup <- as.integer(factor(DF2$Person)) )
  Team     Person DupeGroup
1   30 1, 2, 3, 4         1
2   40     11, 22         2
3   50 1, 2, 3, 4         1
4   60 15, 16, 17         3
5   70 1, 2, 3, 4         1
6   80     11, 22         2

请注意,问题中显示的预期输出要么在某些列条目中添加NAs或空字符串,因为在data.frame中,所有列必须具有相同的行数。对于列表而言,这是不同的,正如您在一些答案中所看到的那样。


第二个选项,但是使用data.table,因为aggregate对于大数据来说往往很慢:

library(data.table)
setDT(DF)[, toString(Person), by=Team][,DupeGroup := .GRP, by=V1][]
   Team         V1 DupeGroup
1:   30 1, 2, 3, 4         1
2:   40     11, 22         2
3:   50 1, 2, 3, 4         1
4:   60 15, 16, 17         3
5:   70 1, 2, 3, 4         1
6:   80     11, 22         2

答案 4 :(得分:2)

使用uniquecombs包中的mgcv

library(mgcv)
library(magrittr) # for the pipe %>%

# Using MrFlick's data
team_names <- sort(unique(dd$Team))
unique_teams <- with(dd, table(Team, Person)) %>% uniquecombs %>% attr("index")
printout <- unstack(data.frame(team_names, unique_teams))

> printout
$`1`
[1] 60

$`2`
[1] 40 80

$`3`
[1] 30 50 70

现在您可以使用类似this answer的内容以表格形式打印它(请注意,这些组是按列排列的,而不是像问题中那样按行排列):

attributes(printout) <- list(names = names(printout)
                             , row.names = 1:max(sapply(printout, length))
                             , class = "data.frame")
> printout
     1    2  3
1   60   40 30
2 <NA>   80 50
3 <NA> <NA> 70
Warning message:
In format.data.frame(x, digits = digits, na.encode = FALSE) :
  corrupt data frame: columns will be truncated or padded with NAs