在数据帧行之间查找唯一值并替换它们(R)

时间:2018-06-07 15:56:43

标签: r dplyr distinct

我有嵌套数据,内部和集群级别观察的ID号。我们称它们为L1ID和L2ID。

L1ID <- c(1,2,3,4,5,6)
L2ID <- c(11,11,22,22,33,33)

两者都有很多变数。我们称之为L1X和L2X的

L1X1 <- rnorm(6,3,1.1)
L1X2 <- rnorm(6,0,.7)
L2X1 <- c(0,1,1,1,0,0)
L2X2 <- c(Blue,Blue,Red,Red,Green,Red)

将矢量组合成数据帧:

df <- data.frame(L1ID,L2ID,L1X1,L1X2,L2X1,L2X2)
df

我有问题。 11和33 L2ID的值不相同。当L2X1应该为0时,ID11在L2X1下的第二个条目为1,而当L2X2为绿色时,ID 33在最后一个条目中为红色。

L1X值应在群集内而不是L2X中不同。我需要一种通过L2ID搜索大型数据库并找到不相同的列值的方法。然后,用所选值替换它们。理想情况下,这将是一个数据帧,其中每个L2ID是单行,然后每列是一个逻辑向量,如果该L2ID中该列的所有值都匹配,则表示True或False。然后用相同的值替换它们。因此,对于ID 11,我需要能够看到L2X1与其中聚集的所有主题不匹配,并且我可以用0替换1,但L2X2全部匹配。

这有意义吗?

我的实际数据集(许可访问权限,因此我无法共享)相当大,并且手动搜索此内容以查找值不匹配的内容是一种痛苦。

到目前为止,我的方法是消除所有L1X变量,使用dplyr的distinct()函数将每一行减少为L2X变量的唯一组合(每个L2ID通常有2个唯一的组合),然后手动搜索差异。通常它是在错误的地方的小数点。

更新:

为了使这些样本数据更能代表我正在使用的内容,我将L2X2更改为字符向量并添加到第3个L2ID中。此外,我几乎有200列和9,000个L2ID(并且由于大多数是双倍的,它大约是18,000个障碍物)。我正在尝试找到一种方法,在搜索它们的值是否匹配时不手动指定每列。尝试过以下内容:

df %>% group_by(L2ID) %>% sapply(identical())

但我从未在Base R中使用same()函数,所以这不起作用。并且仍在努力完成下一步的工作。我赞赏到目前为止的答复;我们将继续努力。

2 个答案:

答案 0 :(得分:0)

我对性能没有任何承诺,但这是一个解决方案,它利用了R中的rle(运行长度编码)函数。当然,假设您提供的示例数据正确地暗示了该值应替换为该组中最常见的值。

> L1ID <- c(1,2,3,4,5,6)
> L2ID <- c(11,11,11,22,22,22)
> L1X1 <- rnorm(6,3,1.1)
> L1X2 <- rnorm(6,0,.7)
> L2X1 <- c(0,0,1,1,1,1)
> L2X2 <- c(13,13,13,8,8,9)
> df <- data.frame(L1ID,L2ID,L1X1,L1X2,L2X1,L2X2)
> df
  L1ID L2ID      L1X1         L1X2 L2X1 L2X2
1    1   11 1.9155828  0.287683782    0   13
2    2   11 2.8383669 -0.693942886    0   13
3    3   11 4.7517203  0.419193550    1   13
4    4   22 2.0092141  0.002223136    1    8
5    5   22 1.2546399 -0.457323727    1    8
6    6   22 0.8622906  0.255975868    1    9

> df %>%
     group_by(L2ID) %>%
     mutate(L2X1_r = rle(L2X1)$values[rle(L2X1)$lengths == max(rle(L2X1)$lengths)],
            L2X2_r = rle(L2X2)$values[rle(L2X2)$lengths == max(rle(L2X2)$lengths)]) %>%
     ungroup()
# A tibble: 6 x 8
   L1ID  L2ID      L1X1         L1X2  L2X1  L2X2 L2X1_r L2X2_r
  <dbl> <dbl>     <dbl>        <dbl> <dbl> <dbl>  <dbl>  <dbl>
1     1    11 1.9155828  0.287683782     0    13      0     13
2     2    11 2.8383669 -0.693942886     0    13      0     13
3     3    11 4.7517203  0.419193550     1    13      0     13
4     4    22 2.0092141  0.002223136     1     8      1      8
5     5    22 1.2546399 -0.457323727     1     8      1      8
6     6    22 0.8622906  0.255975868     1     9      1      8

更新

根据评论和更新的问题,我意识到rle不起作用,因为它假定“多数”值具有长游程编码。这种方法解决了这个问题,并引入了一种不必手动指定每个列进行变异的方法。

> L1ID <- c(1,2,3,4,5,6)
> L2ID <- c(11,11,22,22,33,33)
> L1X1 <- rnorm(6,3,1.1)
> L1X2 <- rnorm(6,0,.7)
> L2X1 <- c(0,1,1,1,0,0)
> L2X2 <- c('Blue','Blue','Red','Red','Green','Red')
> df <- data.frame(L1ID,L2ID,L1X1,L1X2,L2X1,L2X2, stringsAsFactors=F)
> df
  L1ID L2ID     L1X1        L1X2 L2X1  L2X2
1    1   11 4.058659  0.12423215    0  Blue
2    2   11 2.922632  0.30954205    1  Blue
3    3   22 2.719407 -0.33382402    1   Red
4    4   22 1.981046 -0.63617811    1   Red
5    5   33 2.570058 -1.39886373    0 Green
6    6   33 4.471551 -0.05489082    0   Red

> replace_with_right_value = function(col) {
+     tbl = table(col)
+     names(tbl)[tbl == max(tbl)]
+ }

> df %>%
     group_by(L2ID) %>%
     mutate_at(vars(matches('L2X')), replace_with_right_value)
     ungroup()
# A tibble: 6 x 6
   L1ID  L2ID     L1X1        L1X2  L2X1  L2X2
  <dbl> <dbl>    <dbl>       <dbl> <chr> <chr>
1     1    11 4.058659  0.12423215     0  Blue
2     2    11 2.922632  0.30954205     1  Blue
3     3    22 2.719407 -0.33382402     1   Red
4     4    22 1.981046 -0.63617811     1   Red
5     5    33 2.570058 -1.39886373     0 Green
6     6    33 4.471551 -0.05489082     0   Red

replace_with_right_value函数接受一列并返回该向量中最常见的元素。 mutate_at允许您指定要选择的列,这些列是通过vars(matches('L2X'))完成的。如果列不遵循此模式,则需要稍微修改该字符串。匹配接受正则表达式,在这种情况下应该证明非常有用。在L2ID的情况下,问题或数据中没有足够的信息来确定L2X1L2ID == 11 L2X2L2ID == 33选择哪个值}。结果,它返回两者。要强制它选择一个值,例如第一个,请更改函数以返回names(tbl)[tbl == max(tbl)][1]

答案 1 :(得分:0)

我们在此检查L2X1是否与L2ID一致。您可以使用此逻辑轻松添加另一列,以检查L2X2。我们只需检查每个min的{​​{1}}和max值是否相等,如果这些值不相等,我们将替换为L2ID中的min值}。

L2X1_Fixed