#r #dataframe
#r #фрейм данных
Вопрос:
В приведенных ниже данных я хочу отслеживать U
и Value
столбец. Как только значение столбца Value
изменится для строк, имеющих одинаковое значение в U
столбце, я хочу присвоить U
столбцу значение NA
.
Есть предложения о том, как эффективно подойти к этому?
Входные данные
data <- read.table(header = TRUE, text="
U Value Debug
A 1 1231
A 1 41
A 2 -1149
A 2 -2339
B 3 -3529
B 4 -4719
C 5 -5909
C 5 -7099
C 5 -8289
C 6 -9479
C 6 -10669
C 6 -11859
D 7 -13049
D 7 -14239
D 8 -15429
D 8 -16619")
Вывод текущей таблицы
U Value Debug
A 1 1231
A 1 41
A 2 -1149
A 2 -2339
B 3 -3529
B 4 -4719
C 5 -5909
C 5 -7099
C 5 -8289
C 6 -9479
C 6 -10669
C 6 -11859
D 7 -13049
D 7 -14239
D 8 -15429
D 8 -16619
Ожидаемый вывод таблицы
U Value Debug
A 1 1231
A 1 41
NA 2 -1149
NA 2 -2339
B 3 -3529
NA 4 -4719
C 5 -5909
C 5 -7099
C 5 -8289
NA 6 -9479
NA 6 -10669
NA 6 -11859
D 7 -13049
D 7 -14239
NA 8 -15429
NA 8 -16619
Комментарии:
1. Я не понимаю, почему существует несколько групп из нескольких
NA
. Мне кажется, что только первоеU
значение в группе будет присвоеноNA
. Можете ли вы объяснить свой вывод?2. .@TimBiegeleisen — Да. Рассмотрим первые четыре строки
Current Table Output
. Все они имеют одинаковое значение для столбцаU
. Я хочу назначитьNA
всем строкам после первого изменения значения в столбцеValue
. Затем та же операция будет применена к следующему подмножеству данных, имеющих значения столбца какB
, а затемC
и затемD
.
Ответ №1:
Мы можем использовать data.table
. Преобразуйте data.frame
в data.table
( setDT(data)
), сгруппируйте по U
, получите идентификатор длины выполнения Value
столбца (на основе изменения значений, значение rleid
инкрементов), преобразуйте его в двоичный файл с помощью оператора mod ( %%
), который преобразуется в логический путем отрицания ( !
), так что 0 становятся TRUE
и 1 FALSE
, получите индекс строки TRUE
значений ( .I
), извлеките этот столбец ( $V1
) и используйте его как i
для присвоения ( :=
) значений U
NA
library(data.table)
setDT(data)[data[, .I[!rleid(Value) %%2], U]$V1, U := NA]
data
# U Value Debug
# 1: A 1 1231
# 2: A 1 41
# 3: <NA> 2 -1149
# 4: <NA> 2 -2339
# 5: B 3 -3529
# 6: <NA> 4 -4719
# 7: C 5 -5909
# 8: C 5 -7099
# 9: C 5 -8289
#10: <NA> 6 -9479
#11: <NA> 6 -10669
#12: <NA> 6 -11859
#13: D 7 -13049
#14: D 7 -14239
#15: <NA> 8 -15429
#16: <NA> 8 -16619
Обновить
Основываясь на обсуждении с OP, нам нужно назначить NA ‘U’, где ‘Value’ не является first
‘Значением’ для каждого ‘U’
setDT(data)[data[, .I[Value != first(Value)], .(U)]$V1, U := NA]
или та же логика в dplyr
library(dplyr)
data %>%
group_by(U1 = U) %>%
mutate(U = replace(U, Value != first(Value), NA)) %>%
ungroup %>%
select(-U1)
Комментарии:
1. .@akrun — Спасибо. Что
V1
? Могу ли я использовать ваше решение, еслиValue
столбец нечисловой?2. @ChetanArvindPatil Да, вы также можете использовать для нечисловых значений,
rleid
возвращает идентификатор длины выполнения на основе изменений в соседнем элементе. Здесь V1 является выводом столбца по умолчанию.I
, т.е. извлеченный индекс3. @ChetanArvindPatil Вы можете проверить вывод
rleid(c("A", "A", "B", "A", "A"))
4. .@akrun — В больших данных, которые у меня есть, это только замена первого изменения, а затем сохраняет в остальных строках те же
U
значения, что и у него. Есть предположения, почему это так? Данные слишком велики для совместного использования.5. @ChetanArvindPatil если шаблон данных похож на тот, который вы упомянули, он должен работать
v1 <- c("A", "B", "A", "A", "B", "B");!rleid(v1) %% 2# [1] FALSE TRUE FALSE FALSE TRUE TRUE
, если вы проверите здесь, это не только первое изменение, которое становится ИСТИННЫМ
Ответ №2:
Что-то вроде этого?
data %>%
group_by(U) %>%
mutate(
grp = cumsum(!(lag(Value, default = F) == Value)),
U.new = ifelse(grp == 1, as.character(U), NA))
## A tibble: 16 x 5
## Groups: U [4]
# U Value Debug grp U.new
# <fct> <int> <int> <int> <chr>
# 1 A 1 1231 1 A
# 2 A 1 41 1 A
# 3 A 2 -1149 2 NA
# 4 A 2 -2339 2 NA
# 5 B 3 -3529 1 B
# 6 B 4 -4719 2 NA
# 7 C 5 -5909 1 C
# 8 C 5 -7099 1 C
# 9 C 5 -8289 1 C
#10 C 6 -9479 2 NA
#11 C 6 -10669 2 NA
#12 C 6 -11859 2 NA
#13 D 7 -13049 1 D
#14 D 7 -14239 1 D
#15 D 8 -15429 2 NA
#16 D 8 -16619 2 NA
U.new
Здесь я создаю новый столбец, поскольку мы группируем по U
.
В ответ на ваш комментарий, для замены U
на U.new
вы можете сделать
data %>%
group_by(U) %>%
mutate(
grp = cumsum(!(lag(Value, default = F) == Value)),
U.new = if_else(grp == 1, as.character(U), "NA")) %>%
ungroup() %>%
select(U = U.new, Value, Debug)
## A tibble: 16 x 3
# U Value Debug
# <chr> <int> <int>
# 1 A 1 1231
# 2 A 1 41
# 3 NA 2 -1149
# 4 NA 2 -2339
# 5 B 3 -3529
# 6 NA 4 -4719
# 7 C 5 -5909
# 8 C 5 -7099
# 9 C 5 -8289
#10 NA 6 -9479
#11 NA 6 -10669
#12 NA 6 -11859
#13 D 7 -13049
#14 D 7 -14239
#15 NA 8 -15429
#16 NA 8 -16619
Комментарии:
1. .@MauritsEvers — Спасибо. Разве невозможно просто обновить тот же фрейм данных?
2. @ChetanArvindPatil Нет, я не думаю, что это возможно напрямую, потому что вы группируете по
U
. Вы могли бы добавить несколько дополнительных шагов к (1)ungroup
, (2) заменитьU
наU.new
и (3) удалитьU.new
. Смотрите мой обновленный ответ.3. .@MauritsEvers — Большие данные, которые у меня есть, имеют имя столбца, подобное
Data-1
для столбцаU
. Я пробовал этоData-1.new
, но это не работает. Есть предложения о том, как обработать такое имя столбца для вашего кода?4. @ChetanArvindPatil Это довольно плохое (не похожее на R) имя столбца. Но это все равно будет работать, если вы используете обратные ссылки при создании нового столбца.
5. .@MauritsEvers — Отмечено, улучшится. Если столбец
Value
нечисловой, будет ли работать ваш код?
Ответ №3:
Другой вариант с dplyr
заключается в том, чтобы для каждой группы ( U
) найти первую строку, которая Value
отличается от предыдущей, и после этого изменить эти строки на NA
.
library(dplyr)
data %>%
group_by(U) %>%
mutate(U1 = replace(U, row_number() > which.max(diff(Value) != 0), NA))
# U Value Debug U1
# <fct> <int> <int> <fct>
# 1 A 1 1231 A
# 2 A 1 41 A
# 3 A 2 -1149 NA
# 4 A 2 -2339 NA
# 5 B 3 -3529 B
# 6 B 4 -4719 NA
# 7 C 5 -5909 C
# 8 C 5 -7099 C
# 9 C 5 -8289 C
#10 C 6 -9479 NA
#11 C 6 -10669 NA
#12 C 6 -11859 NA
#13 D 7 -13049 D
#14 D 7 -14239 D
#15 D 8 -15429 NA
#16 D 8 -16619 NA
Если в Value
столбце могут быть нечисловые значения, мы можем использовать lag
вместо diff
data %>%
group_by(U) %>%
mutate(U1 = replace(U, row_number() >= which.max(Value != lag(Value)), NA))