在 R 中通过多个 Dataframe 循环管道运算符代码

Looping pipe operator code through multiple Dataframe in R

提问人:Luther_Proton 提问时间:7/4/2022 更新时间:7/4/2022 访问量:128

问:

有谁知道如何通过多个数据帧循环管道运算符代码?

多年来,我命名了不少数据帧(df_1990、df_1991......df_2020)。但是,并非所有年份都包括在内(即 df_1993 年、df_2012 年和 3 年以上不可用)。为了解决这个问题,我手动创建了一个列表来存储循环的所有数据帧(如果有更快的方法,请告诉我)。

df_list = list(df_1990, df_1991, ..., df_2020)
for (i in df_list) {
 ...
 }

数据帧非常简单,只有 2 列(Item(字符字段)和 Cost(数字字段)。

项目 成本
Book_A 3.00
Book_B 5.00
... ...

DataFrame 的示例代码

df = structure(list(Item = structure(c(1L, 1L, 1L, 2L, 2L, 3L, 2L, 
3L, 1L, 2L, 1L, 2L, 1L, 3L, 1L, 2L, 2L, 1L, 3L, 1L), .Label = c("Book A", 
"Book B", "Book C"), class = "factor"), Cost = c(5, 3.5, 12, 
6, 8, 3, 6, 3.5, 3.8, 13, 5.1, 7, 11.5, 3.8, 5.5, 6.5, 13.5, 
5.5, 3.5, 1.2)), class = "data.frame", row.names = c(NA, -20L
))

有谁知道我如何将以下代码添加到...上面的 for 循环代码的一部分?谢谢!

df %>%
  group_by(Item) %>%
  summarise(outlier = mean(Cost), 
            offset = outlier * 0.6, 
            higher_value = outlier + offset, 
            lower_value = outlier - offset) %>%
  left_join(df, by = 'Item') %>%
  transmute(Item, Cost, Outlier = ifelse(Cost < lower_value | Cost > higher_value, 'Y', 'N'))

该代码基本上检测异常值(例如,如果成本比特定项目的大多数平均值高或低 60%),并为每行分别输出一列“Y”和“N”。(代码的功劳归 Ronak Shah 所有)

理想情况下,创建的新列应出现在创建的列表中,以允许导出为 excel 格式

谢谢!

R DataFrame for 循环 数据操作

评论

0赞 Julien 7/4/2022
library(dplyr)

答:

2赞 stefan 7/4/2022 #1

就我个人而言,我会在函数中移动数据整理代码,然后用于遍历数据帧列表。lapply

library(dplyr)

df_list <- list(df, df, df)

prep_data <- function(x) {
  x %>%
    group_by(Item) %>%
    summarise(
      outlier = mean(Cost),
      offset = outlier * 0.6,
      higher_value = outlier + offset,
      lower_value = outlier - offset
    ) %>%
    left_join(x, by = "Item") %>%
    transmute(Item, Cost, Outlier = ifelse(Cost < lower_value | Cost > higher_value, "Y", "N"))
}

df_prep <- lapply(df_list, prep_data)

lapply(df_prep, head, 2)
#> [[1]]
#> # A tibble: 2 × 3
#>   Item    Cost Outlier
#>   <fct>  <dbl> <chr>  
#> 1 Book A   5   N      
#> 2 Book A   3.5 N      
#> 
#> [[2]]
#> # A tibble: 2 × 3
#>   Item    Cost Outlier
#>   <fct>  <dbl> <chr>  
#> 1 Book A   5   N      
#> 2 Book A   3.5 N      
#> 
#> [[3]]
#> # A tibble: 2 × 3
#>   Item    Cost Outlier
#>   <fct>  <dbl> <chr>  
#> 1 Book A   5   N      
#> 2 Book A   3.5 N

如果你想通过循环来做到这一点,那么你可以得到同样的结果,如下所示:for

df_prep <- list()
for (i in seq_along(df_list)) {
  df_prep[[i]] <- prep_data(df_list[[i]])
}
1赞 MarkusN 7/4/2022 #2

为什么不将所有数据放入一个数据帧中:

df_list = list(df_1990 = df_1990, df_1991 = df_1991, ..., df_2020 = df_2020)
df2 = dplyr::bind_rows(df_list, .id = 'Year')

然后,您只需将变量添加到语句中:Yeargroup_by

group_by(Year, Item)

如果需要,可以随时将其转换回数据帧列表:

df2 %>% 
  tidyr::nest(data =  Item:Cost) %>% 
  pull(data, name = Year)

顺便说一句,您还可以通过省略连接来改进异常值检测的代码:

df2 %>%
  group_by(Year, Item) %>%
  mutate(outlier = mean(Cost), 
            offset = outlier * 0.6, 
            higher_value = outlier + offset, 
        lower_value = outlier - offset) %>%
  transmute(Item, Cost, Outlier = if_else(Cost < lower_value | Cost > higher_value, 'Y', 'N'))

使用 而不是将结果复制到组的每一行。mutatesummarisemean(Cost)

评论

0赞 Luther_Proton 7/4/2022
也感谢您对异常值检测代码的改进!