代码之家  ›  专栏  ›  技术社区  ›  Nashh

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

  •  1
  • Nashh  · 技术社区  · 8 年前

    我有一个ID和地址的数据帧。通常,我希望每个循环ID在所有观察中都具有相同的地址,但我的一些ID具有不同的地址。我想定位ID上重复的观察结果,但至少有两个不同的地址。然后,我想为其中一个随机化一个新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可能有两个以上的不同地址,因此应该为每个唯一的地址授予新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 回复  |  直到 8 年前
        1
  •  4
  •   Nashh    8 年前

    这里有一个解决方案 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 如果您想要更漂亮的代码(相同的输出)。

        2
  •  3
  •   moodymudskipper    8 年前

    一种选择是 data.table . 按“ID”分组后, if 数量 unique “Address”大于1,“Address”不等于第一个 唯一的 “Address”,然后获取行索引( .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))