Объединение для l oop и изменение в функции для нескольких кадров данных в R - PullRequest
0 голосов
/ 02 апреля 2020

Я надеюсь, что смогу понять мою проблему. По сути, я хочу создать один и тот же набор переменных в нескольких разных наборах данных (они являются подмножествами исходного набора данных, основанного на выбросах, ответах протеста и т. Д. c.). Я перепробовал много вещей, но я полностью в тупике.

Во-первых, я понимаю, что использование eval (parse (противоречит предложениям), однако, я не самый эффективный кодер, и это работало для моих целей. В любом случае, моя цель в основном создать набор переменных - X_3, X_4, X_5 и др. c. Это годовая сумма (x12) набора других переменных - z1_1, z2_1, z3_1 и др. c. Для этого у меня есть следующий код, который работает, когда я ставлю в каждом имени набора данных, где 'data'.

Редактировать: Спецификации данных

#what it looks like now
  responseid   z3_1 z4_1 z5_1
1          1  4.720 7.08   NA
2          2  1.180   NA 1.18
3          3  1.180   NA 1.18
4          4  2.596 3.54   NA
5          5 15.340   NA   NA
6          6  2.360   NA 2.36

#what i'd like it look like:
  responseid   z3_1 z4_1 z5_1    X_3  X_4  X_5
1          1  4.720 7.08   NA  56.640 84.96    NA
2          2  1.180   NA 1.18  14.160    NA 14.16
3          3  1.180   NA 1.18  14.160    NA 14.16
4          4  2.596 3.54   NA  31.152 42.48    NA
5          5 15.340   NA   NA 184.080    NA    NA
6          6  2.360   NA 2.36  28.320    NA 28.32

#dput
#original
structure(list(responseid = c(1L, 2L, 3L, 4L, 5L, 
6L), z3_1 = c(4.72, 1.18, 1.18, 2.596, 15.34, 2.36), z4_1 = c(7.08, 
NA, NA, 3.54, NA, NA), z5_1 = c(NA, 1.18, 1.18, NA, NA, 2.36),  class = "data.frame", row.names = c(NA, 6L))

#expected
structure(list(responseid = c(1L, 2L, 3L, 4L, 5L, 
6L), z3_1 = c(4.72, 1.18, 1.18, 2.596, 15.34, 2.36), z4_1 = c(7.08, 
NA, NA, 3.54, NA, NA), z5_1 = c(NA, 1.18, 1.18, NA, NA, 2.36), 
    X_3 = c(56.64, 14.16, 14.16, 31.152, 184.08, 28.32), X_4 = c(84.96, 
    NA, NA, 42.48, NA, NA), X_5 = c(NA, 14.16, 14.16, NA, NA, 
    28.32)), class = "data.frame", row.names = c(NA, 6L))

Но я хотел бы сделать это для нескольких наборов данных, поэтому я и хочу использовать Функция для запуска каждого df.

for (i in 3:9){
    X.varname <- paste0("X_",i)
    data <- data %>%
      mutate(
        !!X.varname := eval(parse(text=paste0("z", i, "_1")))*12
      )
  }

Однако, когда я пытаюсь поместить это в функцию (чтобы я мог запустить ее через список фреймов данных), ничего не происходит:

f.test <- function(data){
for (i in 3:9){
    X.varname <- paste0("X_",i)
    data <- data %>%
      mutate(
        !!X.varname := eval(parse(text=paste0("z", i, "_1")))*12
      )
  }
}

Кто-нибудь знает, почему это может быть? Это мой первый вопрос о StackOverflow, поэтому я прошу прощения, если какое-либо форматирование является неправильным.

Ответы [ 2 ]

1 голос
/ 02 апреля 2020

Ничего не происходит, потому что функция ничего не возвращает. Обычно вам не нужно явно return что-то в R, потому что R автоматически возвращает последний объект. Но это для l oop, значит, ничего не возвращает.

Чтобы избежать проблемы, просто укажите, что ваша функция должна возвращать ie. data:

f.test <- function(data){
  for (i in 3:5){
    X.varname <- paste0("X_",i)
    data <- data %>%
      mutate(
        !!X.varname := eval(parse(text=paste0("z", i, "_1")))*12
      )
  }
  return(data)
}

Кстати, вы правы, что eval(parse(x)) не рекомендуется, потому что это опасно и медленно.

Не уверен, что то, что вы показали нам, действительно то, что вы пытаются сделать, но лучший способ сделать это будет:

library(dplyr)
library(stringr)


my_fun <- function(data) {
  data %>% 
    mutate_at(vars(starts_with("z")), .funs = list(TBC=~.*12)) %>% 
    rename_at(vars(ends_with('TBC')), .funs = ~{.x %>% str_extract('\\d') %>% str_c('X_', .)})
}

Более того, так как вам нужно сделать это для нескольких фреймов данных, вы можете использовать @koenniem рекомендацию, чтобы использовать purrr::map(). Поместите каждый фрейм данных в список и примените функцию к каждому элементу списка:

library(purrr)
df2 <- df %>% mutate_at(vars(-responseid), ~.+4)

df_t <- list(df, df2)

df_t %>% 
  map_df(my_fun)
#>    responseid   z3_1  z4_1 z5_1     X_3    X_4   X_5
#> 1           1  4.720  7.08   NA  56.640  84.96    NA
#> 2           2  1.180    NA 1.18  14.160     NA 14.16
#> 3           3  1.180    NA 1.18  14.160     NA 14.16
#> 4           4  2.596  3.54   NA  31.152  42.48    NA
#> 5           5 15.340    NA   NA 184.080     NA    NA
#> 6           6  2.360    NA 2.36  28.320     NA 28.32
#> 7           1  8.720 11.08   NA 104.640 132.96    NA
#> 8           2  5.180    NA 5.18  62.160     NA 62.16
#> 9           3  5.180    NA 5.18  62.160     NA 62.16
#> 10          4  6.596  7.54   NA  79.152  90.48    NA
#> 11          5 19.340    NA   NA 232.080     NA    NA
#> 12          6  6.360    NA 6.36  76.320     NA 76.32
0 голосов
/ 02 апреля 2020

Ничего не происходит, потому что вы присваиваете data аргументу data функции, которая отличается от data от значения в вашей глобальной среде. Вы можете использовать assign(data, YourAssignedValue, envir = .GlobalEnv) или использовать операцию глубокого назначения <<-. В качестве альтернативы, поскольку вы хотите заменить исходные данные, просто верните data примерно так:

f.test <- function(data){
    for (i in 3:5){
        X.varname <- paste0("X_",i)
        data <- data %>%
            mutate(!!X.varname := eval(parse(text=paste0("z", i, "_1")))*12)
    }
    data
}
data <- f.test(data)

Если я могу предложить другой подход; Вы можете создать вложенные наборы данных tibble, используя, например, tibble::tribble, а затем выполнить мутации et c. используя purrr::map.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...