在另一列中标识具有不同值的一个值的重复项

时间:2017-10-30 09:44:26

标签: r duplicates unique

我有一个ID和地址的数据框。通常情况下,我希望每个重复ID在所有观察中都具有相同的地址,但我的一些ID具有不同的地址。我想找到那些在ID上重复的观察,但至少有2个不同的地址。然后,我想为其中一个随机化一个新ID(之前在DF中不存在的ID)。

例如:

ID     Address
1      X
1      X  
1      Y
2      Z
2      Z
3      A
3      B
4      C
4      D
4      E
5      F
5      F
5      F

将返回:

ID    Address
1      X
1      X  
6      Y
2      Z
2      Z
3      A
7      B
4      C
8      D
9      E
5      F
5      F
5      F

所发生的事情是第3次,第7次,第9次和第10次观察得到了新的ID。我将提到ID可能有超过2个不同的地址,因此每个唯一地址都应该为新ID授予权限。

编辑:

我为数据框的较长示例添加了一个代码,rand列应该被忽略但保留在最终输出中。

df <- data.frame(ID = c(1,1,1,2,2,3,3,4,4,4,5,5,5),
             Address = c("x","x","y","z","z","a","b","c","d","e",
                         "f","f","f"),
             rand = sample(1:100, 13))

2 个答案:

答案 0 :(得分:4)

以下是tidyr和函数nest / unnest

的解决方案
library(tidyr)
library(dplyr)
df %>% group_by(ID,Address) %>% nest %>%
  `[<-`(duplicated(.$ID),"ID",max(.$ID, na.rm = TRUE) + 1:sum(duplicated(.$ID))) %>%
  unnest

# # A tibble: 13 x 3
# ID Address  rand
#    <dbl>  <fctr> <int>
#  1     1       x    58
#  2     1       x     4
#  3     6       y    75
#  4     2       z     5
#  5     2       z    19
#  6     3       a    55
#  7     7       b    34
#  8     4       c    53
#  9     8       d    98
# 10     9       e    97
# 11     5       f    13
# 12     5       f    64
# 13     5       f    80

如果您使用magrittr,请将[<-替换为inset,如果您想要更漂亮的代码(相同的输出)。

答案 1 :(得分:2)

选项为data.table。按“ID”分组后,if unique'地址'的数量大于1且'地址'不等于第一个unique'地址',然后获取行索引(.I)并将那些“ID”分配给原始数据集中尚未包含的“ID”

library(data.table)
i1 <- setDT(df)[,  .I[if(uniqueN(Address)>1) Address != unique(Address)[1]], ID]$V1
df[i1, ID := head(setdiff(as.numeric(1:10), unique(df$ID)), length(i1))] 
df
#     ID Address rand
#  1:  1       x   58
#  2:  1       x    4
#  3:  6       y   75
#  4:  2       z    5
#  5:  2       z   19
#  6:  3       a   55
#  7:  7       b   34
#  8:  4       c   53
#  9:  8       d   98
# 10:  9       e   97
# 11:  5       f   13
# 12:  5       f   64
# 13:  5       f   80

或者我们可以使用base R

ids <- names(which(rowSums(table(unique(df)))>1))
i2 <- with(df, ID %in% ids & Address != ave(as.character(Address), 
                     ID, FUN = function(x) x[1]))
df$ID[i2] <- head(setdiff(1:10, unique(df$ID)), sum(i2))