Как избежать этого цикла for для работы со списком

У меня проблема с R, потому что мне нужно выполнить некоторые операции со списком и создать новый фрейм данных с этими значениями из списка. Если я использую цикл for, это занимает очень много времени. И не знаю, как избежать этого цикла for и как сделать это «if + case_when» без цикла for.

В приведенном ниже коде есть комментарии, объясняющие, что я делаю и что происходит.

Большое спасибо!!

#search in all rows of list "total"
for(i in 1:nrow(total)) {

  #Take with total$Cad[[i]] a value from another list
  val1 <- posdi[posdi$cad == str_to_upper(total$Cad[[i]]),]

  #Check if "font" value from val1 is equal to "Taake" and take the value
  val2 <- val1[val1$font == "Taake",]

  #Format date value
  thedate <- as.numeric(format(as.Date(total$TheDate[[i]], format = "%Y-%m-%d"), '%Y%m%d'))

  #And here comes where I can't continue easily. I want to do an IF and make a different 
  #case_when if the result is between 1 and 5 or between 6 and 7
  if (total$dia[[i]] >= 1 & total$dia[[i]] <= 5) {
    fran = case_when(
      total$secs[[i]]>=0 & total$secs[[i]]<1.5 ~ 1,
      total$secs[[i]]>=1.5 & total$secs[[i]]<4 ~ 2,
      total$secs[[i]]>=4 & total$secs[[i]]<8 ~ 3,
      total$secs[[i]]>=8 & total$secs[[i]]<10 ~ 4)
  } else {
    fran = case_when(
      total$secs[[i]]>=0 & total$secs[[i]]<1.5 ~ 5,
      total$secs[[i]]>=1.5 & total$secs[[i]]<4 ~ 6,
      total$secs[[i]]>=4 & total$secs[[i]]<8 ~ 7,
      total$secs[[i]]>=8 & total$secs[[i]]<10 ~ 8)
  }
  
  #and finally, add that "fran" value, those three from the beggining and some from total list to a new dataframe
  datosTel[nrow(datosTel) + 1,] = c(val2$cad, str_to_upper(total$Camp[[i]]), total$numsem[[i]], thedate, total$diasem[[i]], fran, 0)
}
#It works with the "for" loop, but it take so much time (it goes one by one and the list has more than 200K rows).
#How can I do it without that for loop and make the "if + case_when" correctly?

Еще раз спасибо и хорошего дня

Как было сказано ранее, мои проблемы связаны с циклом FOR и теми IF и CASE_WHEN внутри FOR, потому что я не знаю, как это сделать, если цикла нет.

Взгляните на упаковку purrr.

Julian 03.04.2023 10:26

Вы уверены, что у вас есть список, а не data.frame? Если это data.frame, вы можете взглянуть на dplyr и функции, упомянутые Конрадом.

SebSta 03.04.2023 10:35
Стоит ли изучать 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
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Код внутри вашего цикла касается только текущего элемента ([[i]]), и все операции, которые вы выполняете, по умолчанию векторизованы (за исключением if, но мы можем заменить его непосредственно на if_else).

Таким образом, вы можете заменить весь цикл оператором mutate или transmute (они делают то же самое, transmute просто не сохраняет существующие столбцы, поэтому в вашем случае он кажется более подходящим).

Кроме того, вы можете упростить if, объединив две ветви и добавив смещение, зависящее от total$dia.

Наконец, ваше выражение case_when может быть выражено как выражение findInterval.

Далее я предполагаю, что datosTel — это пустая таблица перед вашим циклом, а также делаю некоторые предположения об именах столбцов, которые вам, возможно, потребуется изменить.

datosTel = total %>%
  transmute(
    cad = posdi$cad[posdi$cad == str_to_upper(Cad) & posdi$font == "Taake"],
    Camp = str_to_upper(Camp),
    numsem = numsem,
    thedate = as.numeric(format(as.Date(TheDate, format = "%Y-%m-%d"), '%Y%m%d')),
    diasem = diasem,
    offset = if_else(dia >= 1 & dia <= 5, 0, 4),
    fran = offset + findInterval(secs, c(0, 1.5, 4, 8, 10, Inf)),
    LAST_COLUMN = 0
  ) %>%
  select(-offset)

(Замените LAST_COLUMN фактическим именем столбца.)

Вызов findInterval эквивалентен:

    case_when(
      secs >= 0 & secs < 1.5 ~ 1,
      secs >= 1.5 & secs < 4 ~ 2,
      secs >= 4 & secs < 8 ~ 3,
      secs >= 8 & secs < 10 ~ 4
    )

Кстати, вычисление thedate выглядит очень хитро, но я только что скопировал сюда ваш код.

Konrad Rudolph 03.04.2023 10:49

Спасибо, @konrad-rudolph, все работает!! Как вы видели, я новичок с R С уважением

More 03.04.2023 16:16

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