Сдвиг значений вверх по строкам в фрейме данных в R по группе

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

mock data frame
df<-data.frame(ID=c("a","a","a","a","a","b","b","b","b","b","c","c","c","c","c"),
               var_description = c("description 1", "description 2","description 3","description 4","description 5",
                                   "description 1", "description 2","description 3","description 4","description 5",
                                   "description 1", "description 2","description 3","description 4","description 5"),
               var_value = c(NA,NA,NA,"desc 1 val","desc 2 val",
                             NA,"desc 1 val","desc 2 val","desc 3 val","desc 4 val",
                             NA,NA,NA,NA,"desc 1 val"),
               shift_val = c(3,3,3,3,3,
                             1,1,1,1,1,
                             4,4,4,4,4))

Вот текущее рабочее решение: -


#getting unique vals
unique_id = unique(df$ID)

#initialising dataframe to collect results
df_results<-data.frame()


#function to shift values up
shift <- function(x,n){
  c(x[-(seq(n))],rep(NA,n))
}


#for loop

for (i in unique_id) {
  
  #filtering by each ID
  one_id<-df%>%filter(ID==i)
  
  #getting value to shift values by
  Move_by_val = unique(one_id$shift_val)
  #shifting
  one_id$new_var_value<-shift(one_id$var_value, Move_by_val)
  
  #binding one_id onto df_results
  
  df_results<-rbind(df_results,one_id)
  
}


head(df_results,10)

# ID var_description  var_value shift_val new_var_value
# 1   a   description 1       <NA>         3    desc 1 val
# 2   a   description 2       <NA>         3    desc 2 val
# 3   a   description 3       <NA>         3          <NA>
# 4   a   description 4 desc 1 val         3          <NA>
# 5   a   description 5 desc 2 val         3          <NA>
# 6   b   description 1       <NA>         1    desc 1 val
# 7   b   description 2 desc 1 val         1    desc 2 val
# 8   b   description 3 desc 2 val         1    desc 3 val
# 9   b   description 4 desc 3 val         1    desc 4 val
# 10  b   description 5 desc 4 val         1          <NA>


Используя shift_val, который связан с каждым уникальным df$ID, я могу сдвинуть var_value вверх, где значение соответствует var_description, как показано в столбце new_var_value.

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

Может ли кто-нибудь порекомендовать альтернативное решение, которое дает мне тот же результат, что и то, что у меня есть, но потенциально может быть намного более эффективным? возможно, лучше всего подойдет решение {data.table} или {purrr}, но я ни в одном из них не очень хорошо разбираюсь.

Версия R: 3.6.1

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
105
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Используя свой shift()

shift = function(x, k) c(x[-seq(k)], rep(NA, k)) # replaced n by k 

пытаться

РЕДАКТИРОВАТЬ

Вероятно, это работает на старых версиях R достаточно быстро,

Reduce(
   tapply(df, df$ID, \(i) transform(i, new_var_value = shift(var_description, shift_val[[1L]]))
    ), f = rbind)

— это классический подход «разделить-применить-объединить» и использовать чистую основу R (без зависимостей). дает

   ID var_description  var_value shift_val new_var_value
1   a   description 1       <NA>         3    desc 1 val
2   a   description 2       <NA>         3    desc 2 val
3   a   description 3       <NA>         3          <NA>
4   a   description 4 desc 1 val         3          <NA>
5   a   description 5 desc 2 val         3          <NA>
6   b   description 1       <NA>         1    desc 1 val
7   b   description 2 desc 1 val         1    desc 2 val
8   b   description 3 desc 2 val         1    desc 3 val
9   b   description 4 desc 3 val         1    desc 4 val
10  b   description 5 desc 4 val         1          <NA>
11  c   description 1       <NA>         4    desc 1 val
12  c   description 2       <NA>         4          <NA>
13  c   description 3       <NA>         4          <NA>
14  c   description 4       <NA>         4          <NA>
15  c   description 5 desc 1 val         4          <NA>

ОРИГИНАЛ удален


Данные

df = data.frame(ID = c("a","a","a","a","a","b","b","b","b","b","c","c","c","c","c"),
               var_description = c("description 1", "description 2","description 3","description 4","description 5",
                                   "description 1", "description 2","description 3","description 4","description 5",
                                   "description 1", "description 2","description 3","description 4","description 5"),
               var_value = c(NA,NA,NA,"desc 1 val","desc 2 val",
                             NA,"desc 1 val","desc 2 val","desc 3 val","desc 4 val",
                             NA,NA,NA,NA,"desc 1 val"),
               shift_val = c(3,3,3,3,3,1,1,1,1,1,4,4,4,4,4))

Использование data.table. Сначала избавляемся от ненужных повторов в сдвиге_val и переносим информацию в другую таблицу.

library(data.table)
setDT(df)


df_shift <- df[, unique(.SD), .SDcols = c("ID", "shift_val")]
setkey(df_shift, "ID") # For faster lookup
get_n <- \(id) df_shift[unlist(id), shift_val]
df[, shift_val := NULL] 

df[, var_value := shift(var_value, n = get_n(.BY)),  by = ID]


#         ID var_description  var_value
#     <char>          <char>     <char>
#  1:      a   description 1 desc 1 val
#  2:      a   description 2 desc 2 val
#  3:      a   description 3       <NA>
#  4:      a   description 4       <NA>
#  5:      a   description 5       <NA>
#  6:      b   description 1 desc 1 val
#  7:      b   description 2 desc 2 val
#  8:      b   description 3 desc 3 val
#  9:      b   description 4 desc 4 val
# 10:      b   description 5       <NA>
# 11:      c   description 1 desc 1 val
# 12:      c   description 2       <NA>
# 13:      c   description 3       <NA>
# 14:      c   description 4       <NA>
# 15:      c   description 5       <NA>

Спасибо за это, я работаю со старой версией R (3.6.1), и при запуске решения get_n <- \(id) df_shift[unlist(id), shift_val] вызывает ошибку. Подскажите, пожалуйста, есть ли способ адаптировать это для моей текущей версии? Спасибо

metaltoaster 01.05.2024 16:50

@metaltoaster, я думаю, было бы полезно, если бы вы добавили в свой вопрос некоторую информацию о вашем сеансе, например, версию R и версии пакета для dplyr, purrr и data.table, чтобы пользователи не догадывались, что может работать для вас.

LMc 01.05.2024 16:55

Спасибо @LMc, сейчас обновлю.

metaltoaster 01.05.2024 16:56

@metaltoaster. Используйте function(id) вместо \(id) на старом R.

s_baldur 01.05.2024 22:20
Ответ принят как подходящий

Вот опция purrr, которая должна работать в более старых версиях:

library(purrr)

shift <- function(dat){
  amt <- dat$shift_val[1]
  within(dat, new_var_val <-  c(dat$var_value[-seq_len(amt)], rep(NA, amt)))
}

df %>% 
  split(. , .$ID) %>% 
  map_dfr(shift)

Выход

   ID var_description  var_value shift_val new_var_val
1   a   description 1       <NA>         3  desc 1 val
2   a   description 2       <NA>         3  desc 2 val
3   a   description 3       <NA>         3        <NA>
4   a   description 4 desc 1 val         3        <NA>
5   a   description 5 desc 2 val         3        <NA>
6   b   description 1       <NA>         1  desc 1 val
7   b   description 2 desc 1 val         1  desc 2 val
8   b   description 3 desc 2 val         1  desc 3 val
9   b   description 4 desc 3 val         1  desc 4 val
10  b   description 5 desc 4 val         1        <NA>
11  c   description 1       <NA>         4  desc 1 val
12  c   description 2       <NA>         4        <NA>
13  c   description 3       <NA>         4        <NA>
14  c   description 4       <NA>         4        <NA>
15  c   description 5 desc 1 val         4        <NA>

просто используйте lead из dplyr:

Обновлено: поскольку вы используете более старую версию, используйте:

df %>%
   group_by(ID) %>%
   mutate(var_value1 = lead(var_value, shift_val[1])) %>%
   ungroup()

df %>%
   mutate(var_value1 = lead(var_value,shift_val[1]), .by = ID)

   ID var_description  var_value shift_val var_value1
1   a   description 1       <NA>         3 desc 1 val
2   a   description 2       <NA>         3 desc 2 val
3   a   description 3       <NA>         3       <NA>
4   a   description 4 desc 1 val         3       <NA>
5   a   description 5 desc 2 val         3       <NA>
6   b   description 1       <NA>         1 desc 1 val
7   b   description 2 desc 1 val         1 desc 2 val
8   b   description 3 desc 2 val         1 desc 3 val
9   b   description 4 desc 3 val         1 desc 4 val
10  b   description 5 desc 4 val         1       <NA>
11  c   description 1       <NA>         4 desc 1 val
12  c   description 2       <NA>         4       <NA>
13  c   description 3       <NA>         4       <NA>
14  c   description 4       <NA>         4       <NA>
15  c   description 5 desc 1 val         4       <NA>

К вашему сведению, пользователь, похоже, использует более старую версию R, поэтому я сомневаюсь, что .by доступен. ОП, возможно, захочет связаться с group_by(ID).

LMc 01.05.2024 17:03

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