Как я могу передать переменные dataframe в цикл for, используя каналы с dplyr? - PullRequest
0 голосов
/ 29 октября 2019

Я пытаюсь выполнить некоторые вычисления для подмножеств моего df, используя цикл for в конце канала dplyr, но переменные, которые я передаю в цикл for из df, не распознаются.

Я пытался выполнить шаги из этого поста: использовать для цикла с каналами в R . По сути, я обертываю цикл for в определенной пользователем функции и передаю df в функцию по каналам.

Я использую набор данных о продажах продуктов и пытаюсь рассчитать средние продажи каждой парыпериоды внутри каждого квартала для каждого продукта (своего рода базис продаж для рекламных акций). Например, мой первый проход через подмножество вычислит среднее значение периодов 2 и 3, пропуская 1. Мой второй проход исключит период 2 и вычислит средние продажи для 1 и 3 и т. Д.

#Create dataframe
Article <- rep(1:3, each = 6)
Quarter <- rep(1:2, each = 3, 3)
Period <- rep(1:3, 6)
Sales <- sample(10:20, 18, replace = T)

df <-data.frame(Article, Quarter, Period, Sales)

foo <- function(x){
  for (i in unique(Period)) {
    filter(Period != i) %>%
      summarize(average_sales = mean(Sales))
  } 
  return(x)
}

df <- df %>% 
  group_by(Article, Quarter) %>%
  foo() 

#Desired resultant df:
average_sales <- c(14.5, 16.5, 12, 12, 16, 15, 16.5, 12.5, 16, 15, 14, 18, 11.5, 11, 11.5, 16, 16, 12)
df$average_sales <- average_sales
print(df, row.names = F)
Article Quarter Period Sales average_sales
      1       1      1    14          14.5
      1       1      2    10          16.5
      1       1      3    19          12.0
      1       2      1    19          12.0
      1       2      2    11          16.0
      1       2      3    13          15.0
      2       1      1    12          16.5
      2       1      2    20          12.5
      2       1      3    13          16.0
      2       2      1    17          15.0
      2       2      2    19          14.0
      2       2      3    11          18.0
      3       1      1    11          11.5
      3       1      2    12          11.0
      3       1      3    11          11.5
      3       2      1    12          16.0
      3       2      2    12          16.0
      3       2      3    20          12.0

Я знаю, что этот код все еще не дает мне мой конечный результат, который в идеале был бы пятой переменной в df, которая содержит для каждого периода средние продажи двух других периодов, но это то, где я застрял. Я даже не уверен, является ли цикл for лучшим / наиболее эффективным способом решения этой проблемы (я ограниченный R-кодер и не знаком со всем набором инструментов Tidyverse), но есть какие-либо предложения о том, как завершитьDataFrame также будет принята с благодарностью. Спасибо!

Ответы [ 2 ]

0 голосов
/ 29 октября 2019

Превращение моих комментариев в ответ с несколькими упрощенными примерами, которые помогут вам понять, как исправить вашу функцию:

foo1 <- function(x) {
  1 + 2
  return(x)
}

foo1(0)
# [1] 0

foo1 - это моя упрощенная версия вашей функции. In принимает аргумент x, делает что-то, что не использует x, а затем возвращает x. Это бессмысленная функция - не имеет значения, что мы делаем 1 + 2, потому что ничего не сделано с результатом. В последней строке foo1 возвращает то же значение, которое было ему передано, нетронутым.

foo2 <- function(x) {
  x + 1
  return(x)
}

foo2(0)
# [1] 0

foo2 немного лучше, но в конечном счете одинаково бессмысленно. Вычисление в середине использует x, что логически является шагом вперед, но результат, x + 1, не сохраняется, и функция по-прежнему возвращает исходный x, который был передан.

foo3 <- function(x) {
  y <- x + 1
  return(y)
}

foo3(0)
# [1] 1

Наконец, функция, которая что-то делает! foo3 добавляет 1 к своему вводу, изменяет ввод для сохранения этого результата в новую переменную y (она также может изменить x, x <- x + 1), а затем возвращает измененную переменную.

С циклом for вы не можете просто сделать y <- for(...), нам нужно выполнить присваивание внутри цикла:

foo4 <- function(x) {
  for(i in 1:3) {
    y <- x + i
  }
  return(y)
}

foo4(0)
# [1] 3

foo4 показываетраспространенная ошибка новичка - y изменяется каждый раз в цикле, но каждый раз перезаписывается. y будет x + 1, в первый раз, затем y будет x + 2, тогда когда i равно 3 y будет x + 3, без памяти предыдущих итераций. Нам нужно дать y некоторую длину, чтобы она могла хранить каждую итерацию отдельно.

foo5 <- function(x) {
  y <- numeric(3)
  for(i in 1:3) {
    y[i] <- x + i
  }
  return(y)
}

foo5(0)
# [1] 1 2 3

foo5 - это хорошо! Мы инициализируем y, чтобы иметь правильную длину, и каждая итерация цикла сохраняет свой результат в другой части y, а затем в конце возвращается все y.

foo <- function(x) {
  y <- list() # with a `list`, we don't absolutely need to specify the length upfront
  for(i in unique(x$Period)) {
    # use [[ for list assignment
    y[[i]] <- x %>%
      filter(Period != i) %>%
      summarize(
        period_excluded = i, # we'll use this to keep track 
        average_sales = mean(Sales)
      )
  } 
  # do ourselves a favor and turn the list of data frames into a single data frame 
  # with bind_rows before returning
  return(bind_rows(y))
}

foo(df)
#   period_excluded average_sales
# 1               1      14.58333
# 2               2      14.16667
# 3               3      15.58333
0 голосов
/ 29 октября 2019

Если мы ищем способ получить mean элементов, отличных от «Продажи» для определенного «периода», получим разницу «Продажи» с sum «Продажи» длякаждый «Статья», «Квартал», и разделить на длину группы -1.

library(dplyr)
df %>%
   group_by(Article, Quarter) %>%
   mutate(average_sales = (sum(Sales)- Sales)/(n()-1))
# A tibble: 18 x 5
# Groups:   Article, Quarter [6]
#   Article Quarter Period Sales average_sales
#     <int>   <int>  <int> <int>         <dbl>
# 1       1       1      1    14          14.5
# 2       1       1      2    10          16.5
# 3       1       1      3    19          12  
# 4       1       2      1    19          12  
# 5       1       2      2    11          16  
# 6       1       2      3    13          15  
# 7       2       1      1    12          16.5
# 8       2       1      2    20          12.5
# 9       2       1      3    13          16  
#10       2       2      1    17          15  
#11       2       2      2    19          14  
#12       2       2      3    11          18  
#13       3       1      1    11          11.5
#14       3       1      2    12          11  
#15       3       1      3    11          11.5
#16       3       2      1    12          16  
#17       3       2      2    12          16  
#18       3       2      3    20          12  

данные

df <- structure(list(Article = c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L), Quarter = c(1L, 1L, 1L, 
2L, 2L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 2L, 2L, 2L), 
    Period = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 
    1L, 2L, 3L, 1L, 2L, 3L), Sales = c(14L, 10L, 19L, 19L, 11L, 
    13L, 12L, 20L, 13L, 17L, 19L, 11L, 11L, 12L, 11L, 12L, 12L, 
    20L)), row.names = c(NA, -18L), class = "data.frame")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...