Пометка первой строки по группе в data.table

В таблице данных ниже я хочу пометить первую строку каждой группой.

  temp_dt <- data.table(date = as.Date(c("2000-01-01","2000-03-31","2000-07-01","2000-09-30", 
                                     "2001-01-01","2001-03-31","2001-07-01","2001-09-30",
                                     "2000-01-01","2000-03-31","2000-07-01","2000-09-30", 
                                     "2001-01-01","2001-03-31","2001-07-01","2001-09-30",
                                     "2000-01-01","2000-03-31","2000-07-01","2000-09-30", 
                                     "2001-01-01","2001-03-31","2001-07-01","2001-09-30")),
                    group = c(1,1,1,1,1,1,1,1,
                              2,2,6,6,6,8,8,8,
                              3,3,3,3,4,4,4,4))

Ниже приведен ожидаемый результат после добавления флага.

> temp_dt
          date group flag
 1: 2000-01-01     1    1
 2: 2000-03-31     1    0
 3: 2000-07-01     1    0
 4: 2000-09-30     1    0
 5: 2001-01-01     1    0
 6: 2001-03-31     1    0
 7: 2001-07-01     1    0
 8: 2001-09-30     1    0
 9: 2000-01-01     2    1
10: 2000-03-31     2    0
11: 2000-07-01     6    1
12: 2000-09-30     6    0
13: 2001-01-01     6    0
14: 2001-03-31     8    1
15: 2001-07-01     8    0
16: 2001-09-30     8    0
17: 2000-01-01     3    1
18: 2000-03-31     3    0
19: 2000-07-01     3    0
20: 2000-09-30     3    0
21: 2001-01-01     4    1
22: 2001-03-31     4    0
23: 2001-07-01     4    0
24: 2001-09-30     4    0
          date group flag

Вот решение, которое я пробовал (это быстро), но оно не работает должным образом.

temp_dt[, flag := if (identical(.I, 1)) 1 else 0, by = .(group)]

Поскольку я имею дело с миллионами строк, ключевым фактором решения является производительность. Я ищу только решение data.table.

Другие решения, представленные на SO, слишком медленные для моего требования.

Я думаю, что Billy34 использует rowid(group) лучше всего, но буквальное улучшение вашего if кода будет temp_dt[, flag := +(seq_len(.N) == 1), by = group]; специальная переменная .I не учитывает группы, как это видно на примере temp_dt[, i := .I, by = group].

r2evans 31.01.2023 14:23
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
64
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете использовать функцию rowid. Это даст добавочный индекс, начинающийся с 1, для каждой группы, определяемой данной переменной (переменными) группировки. Обнаружение первой строки выполняется просто путем сравнения с 1.

temp_dt[, flag := rowid(group)==1]

В качестве бонуса для обнаружения последней строки группы (.N обозначает количество строк текущей группы)

temp_dt[, flag := rowid(group)==.N]

Я согласен. Типа ответ в процессе. Отредактировано до окончательного ответа. Спасибо

Billy34 31.01.2023 14:29

Этот способ находит самую раннюю строку по дате для каждой группы, а затем устанавливает flag == 1 для этих строк.

temp_dt[temp_dt[, .I[date == min(date)], by = .(group)]$V1, flag := 1]

# set the rest of the column to 0
temp_dt[is.na(flag), flag := 0]

Вы можете решить свою проблему следующим образом:

temp_dt[, flag := +!duplicated(group)]
# or
temp_dt[, flag := match(seq_len(.N), 1, 0), by=group]


          date group  flag
 1: 2000-01-01     1     1
 2: 2000-03-31     1     0
 3: 2000-07-01     1     0
 4: 2000-09-30     1     0
 5: 2001-01-01     1     0
 6: 2001-03-31     1     0
 7: 2001-07-01     1     0
 8: 2001-09-30     1     0
 9: 2000-01-01     2     1
10: 2000-03-31     2     0
11: 2000-07-01     6     1
12: 2000-09-30     6     0
13: 2001-01-01     6     0
14: 2001-03-31     8     1
15: 2001-07-01     8     0
16: 2001-09-30     8     0
17: 2000-01-01     3     1
18: 2000-03-31     3     0
19: 2000-07-01     3     0
20: 2000-09-30     3     0
21: 2001-01-01     4     1
22: 2001-03-31     4     0
23: 2001-07-01     4     0
24: 2001-09-30     4     0

Хотя я считаю, что в конечном итоге принятый ответ является лучшим, мне очень нравятся оба этих варианта.

diomedesdata 01.02.2023 06:38

Другие вопросы по теме