Я не даю никаких обещаний по производительности, но это одно решение, которое использует функцию 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]