Добавление столбцов к фреймам данных в цикле double for

#r #for-loop

#r #для цикла

Вопрос:

У меня следующая настройка

 df_names <- c("df1", "df2", "df3")
df1 <- tibble("1" = "hallo")
df2 <- tibble("1" = "hallo")
df3 <- tibble("1" = "hallo")
missing_columns <- c("2", "3")
 

Моя цель — добавить к каждому фрейму данных столбцы, которые видны в missing_columns .

Я пытался

 for(i in df_names){
  
  for(j in missing_columns){
    
    get(i)[, j] <- ""
    
  }
  
}

Error in get(i) <- `*vtmp*` : could not find function "get<-"
 

и

 for(i in df_names){
  
  for(j in missing_columns){
    
    assign(get(i)[, j], "")
    
  }
  
}

Error: Can't subset columns that don't exist.
x Column `2` doesn't exist.
 

Конечно, столбец 2 не существует, поэтому я хочу его добавить.

Комментарии:

1. Просто сделайте df1[["2"]] <- "foo"

2. Это не сработало бы для меня, поскольку я пишу о чем-то, где столбцы, которые нужно добавить, и количество фреймов данных различаются. Вот почему у меня есть вектор имен фреймов данных и вектор отсутствующих столбцов. И именно поэтому я подумал, что использование for-цикла может быть правильным выбором.

Ответ №1:

Вам необходимо назначить объект глобальной среде, чтобы иметь к ним доступ после выполнения кода:

 library(tidyverse)

df_names <- c("df1", "df2", "df3")
df1 <- tibble("1" = "hallo")
df2 <- tibble("1" = "hallo")
df3 <- tibble("1" = "hallo")
missing_columns <- c("2", "3")

df1
#> # A tibble: 1 x 1
#>   `1`  
#>   <chr>
#> 1 hallo
df2
#> # A tibble: 1 x 1
#>   `1`  
#>   <chr>
#> 1 hallo

expand_grid(
  col = missing_columns,
  df = df_names
) %>%
  mutate(
    new_df = map2(col, df, ~ {
      res <- get(.y)
      res[[.x]] <- "foo"
      assign(.y, res, envir = globalenv())
    })
  )
#> # A tibble: 6 x 3
#>   col   df    new_df          
#>   <chr> <chr> <list>          
#> 1 2     df1   <tibble [1 × 2]>
#> 2 2     df2   <tibble [1 × 2]>
#> 3 2     df3   <tibble [1 × 2]>
#> 4 3     df1   <tibble [1 × 3]>
#> 5 3     df2   <tibble [1 × 3]>
#> 6 3     df3   <tibble [1 × 3]>

df1
#> # A tibble: 1 x 3
#>   `1`   `2`   `3`  
#>   <chr> <chr> <chr>
#> 1 hallo foo   foo
df2
#> # A tibble: 1 x 3
#>   `1`   `2`   `3`  
#>   <chr> <chr> <chr>
#> 1 hallo foo   foo
 

Создано 2021-12-09 пакетом reprex (v2.0.1)

Ответ №2:

Также зависит от вашей конечной цели, возможно, этот подход может быть полезен для вас.

 df_names <- c("df1", "df2", "df3")
# note the small change in sample data
df1 <- tibble("1" = "hallo")
df2 <- tibble("2" = "hallo")
df3 <- tibble("3" = "hallo")

# I suggest to work with required columns, what is not there becomes missing
required <- c("1", "2", "3")

dfs <- lapply(df_names, function(df) {
  t <- get(df)
  t[setdiff(required, names(t))] <- NA
  t
})

dfs

[[1]]
# A tibble: 1 x 3
  `1`   `2`   `3`  
  <chr> <lgl> <lgl>
1 hallo NA    NA   

[[2]]
# A tibble: 1 x 3
  `2`   `1`   `3`  
  <chr> <lgl> <lgl>
1 hallo NA    NA   

[[3]]
# A tibble: 1 x 3
  `3`   `1`   `2`  
  <chr> <lgl> <lgl>
1 hallo NA    NA   

# if you want to combine the data anyhow
do.call("rbind", dfs)

# A tibble: 3 x 3
  `1`   `2`   `3`  
  <chr> <chr> <chr>
1 hallo NA    NA   
2 NA    hallo NA   
3 NA    NA    hallo