Поиск уникальных значений между строками фрейма данных и их замена (R) - PullRequest
0 голосов
/ 07 июня 2018

У меня есть вложенные данные с идентификационными номерами для наблюдений на внутри- и кластерном уровне.Давайте назовем их 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 не идентичны.У идентификатора 11 есть 1 для 2-й записи в L2X1, когда он должен быть 0, и у идентификатора 33 есть красный в последней записи для L2X2, когда он должен быть зеленым.

Значения L1X должны отличаться в пределах кластера, но неL2Xs.Мне нужен способ поиска большой базы данных по L2ID и найти значения столбцов, которые не идентичны.Затем замените их выбранным значением.В идеале это должен быть фрейм данных, в котором каждый L2ID представляет собой одну строку, а затем каждый столбец представляет собой логический вектор, который говорит True или False, если все значения в этом столбце для этого L2ID совпадают.И затем замените их всех одинаковыми значениями.Итак, для идентификатора 11 мне нужно убедиться, что L2X1 не подходит для всех объектов, сгруппированных в нем, и что я могу заменить 1 на 0, но все L2X2 совпадают.

Имеет ли это смысл?

Мой фактический набор данных (лицензированный доступ, поэтому я не могу поделиться им) довольно большой, и поиск этой вещи там, где значения не совпадают, - боль.

До сих пор мой подход заключался в том, чтобы исключить все переменные L1X, использовать функцию dplyr diver (), чтобы привести каждую строку к уникальным комбинациям переменных L2X (каждый L2ID обычно имеет 2 уникальные комбинации), а затем выполнить поиск вручнуюза расхождения.Часто это не десятичная точка в неправильном месте.

Обновление:

Чтобы сделать эти примерные данные более репрезентативными для того, с чем я работаю, я изменил L2X2 на символьный вектор и добавил в третьемL2ID.Кроме того, у меня есть почти 200 столбцов и 9000 L2ID (и, поскольку большинство удваивается, получается около 18000 человек).Я пытаюсь найти способ не указывать вручную каждый столбец при поиске, если их значения совпадают.Попробовал что-то вроде следующего:

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

Но я никогда не использовал функцию identifier () в Base R, поэтому это не сработало.И все еще работаю над тем, что делать дальше.Я ценю ответы до сих пор;Я буду продолжать работать над этим, пока мы идем.

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Здесь мы проверяем, соответствует ли L2X1 для L2ID.Вы можете легко добавить другой столбец, используя эту логику, чтобы также проверить L2X2.Мы просто проверяем, равны ли значения min и max каждого L2ID, если эти значения не равны, мы заменяем значение min в L2X1_Fixed.

df %>% group_by(L2ID) %>% mutate(Test= ifelse(min(L2X1)==max(L2X1), TRUE,FALSE)) %>%
      mutate(L2X1_Fixed = ifelse(Test ==FALSE, min(L2X1), L2X1))

# A tibble: 6 x 8
# Groups:   L2ID [2]
   L1ID  L2ID     L1X1        L1X2  L2X1  L2X2  Test L2X1_Fixed
  <dbl> <dbl>    <dbl>       <dbl> <dbl> <dbl> <lgl>      <dbl>
1     1    11 2.355470 -1.53195614     0    13 FALSE          0
2     2    11 3.784859  0.20900278     0    13 FALSE          0
3     3    11 3.339077 -0.19772481     1    13 FALSE          0
4     4    22 2.512764  0.18222493     1     8  TRUE          1
5     5    22 1.176079  0.04175856     1     8  TRUE          1
6     6    22 3.688449 -0.42174624     1     9  TRUE          1
0 голосов
/ 07 июня 2018

Я не даю никаких обещаний по производительности, но это одно решение, которое использует функцию rle (кодирование длины выполнения) в R. Это, конечно, предполагает, что приведенные вами примеры данных правильно подразумевают, что значениеследует заменить на наиболее распространенное значение в этой группе.

> 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')).Если столбцы не следуют этому шаблону, вам нужно немного изменить эту строку.Matches принимает регулярное выражение, которое должно оказаться очень полезным в этом случае.В этом случае L2ID в вопросе или данных недостаточно информации, чтобы определить, какое значение выбрать для L2X1, когда L2ID == 11 или L2X2, когда L2ID == 33.В результате он возвращает оба.Чтобы заставить его выбрать значение, такое как первое, измените функцию, чтобы она возвращала names(tbl)[tbl == max(tbl)][1]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...