добавление новых переменных во фрейм данных с помощью функций выбора и изменения dplyr в цикле for - PullRequest
0 голосов
/ 12 мая 2018

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

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

df <- data.frame("Jan.2012" = c(1, 4, 5, 6), "Feb.2012" = c(3, 5, 7, 9),
 "Jan.2013" = c(6, 8, 9, 10), "Feb.2013" = c(7, 5, 11, 13), "Jan.2014" = c(6, 8, 9, 11), 
 "Feb.2014" = c(7, 3, 5, 9))

Новые переменные будут называться TotalYr2012, TotalYr2013 и т. Д. Например, TotalYr2012 = c (4, 9, 12, 15) и т. Д.

Я пытаюсь перебрать цикл for (не лучшая практика, я знаю) для генерации этих переменных.Я знаю, что делаю что-то не так с оператором assign, а также получаю сообщение об ошибке.

for (i in 2012:2014) {
  varname <- paste("TotalYr", i, sep = "")
    assign(df$varname, df %>% select(contains("i")) %>% 
     mutate(varname = sum()))
}

Спасибо за вашу помощь!

Ответы [ 2 ]

0 голосов
/ 12 мая 2018

У вас много проблем.

  1. $ не работает с переменными.Вместо этого используйте [ или [[. См. Этот R-FAQ для дополнительной информации .Кроме того, ваш отступ грязный, давайте сделаем его согласованным:

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      assign(df[[varname]], df %>% select(contains("i")) %>% 
        mutate(varname = sum()))
    }
    
  2. assign не требуется, просто используйте <- (или =).Вы почти никогда не должны использовать assign().

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      df[[varname]] <- df %>% select(contains("i")) %>% 
        mutate(varname = sum()))
    }
    
  3. "i" - это строка, ее значением всегда является буква "i", так же как значение 2 являетсявсегда 2.Даже в contains() вы хотите использовать значение , которое вы присвоили объекту i (хотя это значение действительно должно быть строкой, чтодолжно иметь класс character):

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      df[[varname]] <- df %>% select(contains(as.character(i))) %>% 
        mutate(varname = sum()))
    }
    
  4. mutate и select возвращать фреймы данных, что означает, что ваш код пытается присвоить одно-фрейм данных столбца do df[[varname]].Мы хотим назначить только вектор столбца, а не весь фрейм данных.Таким образом, мы вытаскиваем вектор столбца с dplyr::pull

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      df[[varname]] <- df %>% select(contains(as.character(i))) %>% 
        mutate(varname = sum())) %>%
        pull()
    }
    
  5. Типом sum() в вашей консоли - вы получаете 0.Вам нужно дать что-то sum().Давайте избавимся от mutate полностью и просто sum pull ed вектора, так что нам не нужно беспокоиться о его названии:

    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      df[[varname]] <- df %>% select(contains(as.character(i))) %>% 
        pull %>% sum
    }
    
  6. Хорошо,это вроде работает сейчас.Но вы добавляете эти новые значения в старый фрейм данных, в котором есть несколько строк.Новые значения - это просто отдельные значения, поэтому они «перерабатываются», повторяются в каждой строке фрейма данных.Давайте вместо этого создадим новый фрейм данных result, который будет иметь только одну строку для нашего результата:

    result = list()
    for (i in 2012:2014) {
      varname <- paste("TotalYr", i, sep = "")
      result[[varname]] <- df %>% select(contains(as.character(i))) %>% 
        pull %>% sum
    }
    result = as.data.frame(result)
    result
    #   TotalYr2012 TotalYr2013 TotalYr2014
    # 1          24          36          24
    
  7. Теперь он работает и дает рабочее решение.Тем не менее, это все еще грязно.for петли обычно не нужны.У нас есть намного лучшие инструменты для очистки данных.

    # See MKR's answer. It's the way you should actually do this.
    
0 голосов
/ 12 мая 2018

Вы можете избежать for-loop, используя функции tidyr::gather и zoo::yearmon для расчета итогов за каждый год.

library(tidyverse)
library(zoo)

df %>% gather(Date, value) %>%
  mutate(Date = as.yearmon(Date,"%b.%Y")) %>%
  group_by(Year = year(Date)) %>%
  summarise(Total = sum(value)) %>%
  spread(Year, Total)

# # A tibble: 1 x 3
#     `2012` `2013` `2014`
# *   <dbl>  <dbl>  <dbl>
# 1   40.0   69.0   58.0  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...