【问题标题】:How to use purrr::map to sum nas for each dataframe in a list如何使用 purrr::map 为列表中的每个数据帧求和 nas
【发布时间】:2020-10-14 18:30:45
【问题描述】:

我有一个空气污染站的数据框,每个站都有一个代码 c,以及污染物 nox、no2、pm10、pm25 的测量值。例如:


kcl_data
+-----------------------+--------+---------+----------+-------+------+--+
|        date           |  nox   |  no2    |  pm10    | pm25  | code |  |
+-----------------------+--------+---------+----------+-------+------+--+
| 2018-01-01 00:00:00   |  18.5  |   14.6  |  11.4    |   9   |  BL0 |  |
| 2018-01-01 01:00:00   |  20.2  |  17.3   |   8.9    |  7.2  | BL0  |  |
| 2018-01-01 02:00:00   | 20.3   | 17.5    |   6.9    |  6    | BL0  |  |
| 2018-01-01 03:00:00   | na     | 17.3    |   5.6    |  1.5  | BL0  |  |
| 2018-01-01 04:00:00   | 14.3   | 12.9    |   na     |  4.9  | BL0  |  |
+-----------------------+--------+---------+----------+-------+------+--+

每个站点在不同时间记录许多不同污染物的值,我想使用 purrr::map(或 map_df)返回一个数据框,其中包含每个污染物和站点的空值数。结果应如下所示:


+--------+--------+---------+---------+------+--+
| nox_na | no2_na | pm10_na | pm25_na | code |  |
+--------+--------+---------+---------+------+--+
|      1 |      0 |       0 |       1 | BL0  |  |
|      0 |      2 |       0 |       0 | BQ7  |  |
|      3 |      0 |       0 |       6 | BZ2  |  |
+--------+--------+---------+---------+------+--+


问题是我编写的函数更像是 ::map 后跟 ::reduce 而不是 ::map。这是我尝试过的代码:

nas_by_code_and_pollutant <- function(c,p) {
  df_sub <- filter(kcl_data, code %in% c) %>% 
    select(p)
  sum_na <- map(df_sub, ~sum(is.na(.)))
  sum_na
}

# this seems to work OK for one code and one pollutant
nas_by_code_and_pollutant('BQ7','nox') # $nox [1] 240 

# Now I want to output a dataframe of station codes and the number of nas by pollutant 
result_df <- map_df(codes, ~nas_by_code_and_pollutant(.codes,'nox'))
result_df

但是,result_df 是对每个代码(如 map 和 reduce)的总 nas 求和,而不是生成一个数据帧,其中包含一列站点代码和污染物的 nas 数量。

# A tibble: 1 x 1
     nox
   <int>
1 274709

大概这也可以很简单地使用 groupby(code) 并对 nas 求和来完成,但我想正确地使用 purrr 方式。感谢您的帮助!

【问题讨论】:

  • 抱歉,不,这是我最初的设置,它只是一个保存所有数据的数据框。我确实尝试了 map(.x, f) ,其中 x 是一个数据帧列表,每个数据帧都有一个代码,但也无法让它工作
  • 我会使用group_split,然后遍历list。也许这对你有帮助。

标签: r purrr


【解决方案1】:

如果是单个数据集,

library(dplyr)
library(purrr)
kcl_data %>%
      group_by(code) %>%
      summarise(across(nox:pm25, ~ sum(is.na(.))))

如果我们需要使用map,那么splitgroup_split的数据

kcl_data %>%
     group_split(code) %>%
     map_dfr(~ .x %>% 
              summarise(code = first(code), across(nox:pm25, ~ sum(is.na(.)))))

如果我们有data.frames 中的list,那么我们用map 循环遍历list

map(kcl_data_list, ~ .x %>% # // .x => individual dataset
             group_by(code) %>%
             summarise(across(nox:pm25, ~ sum(is.na(.))))

           

【讨论】:

  • 这很快 :-) 在这种情况下,如果 kcl_data 是数据帧列表,那么 .x 指的是什么?
  • @LucieCBurgess 这是我早期的代码。在这种情况下,.x 将是每个 list 中的单个 data.frame。那么你只需要我的第一个代码块复制/粘贴中来自 group_by 的代码
  • @LucieCBurgess 在第二种情况下,我们将数据拆分为 data.frames 列表,其中每个元素用于特定代码。然后循环。用map 在列表上,这里.x 表示该“代码”的每个列表元素,对列进行汇总并返回“代码”(因为这里没有 group 属性
  • 嗨@akrun,您能否使用数据框列表重新发布地图解决方案,因为它已经消失了?谢谢,超级优雅的答案。抱歉,我的回复延迟了,孩子们现在已经睡觉了!
  • 太好了,我明白了,谢谢!非常感谢(和闪电般的速度):-) 所以基本上 .x 指的是被映射的列表中的每个元素......我认为语法的这个重要元素对我来说并不清楚。
猜你喜欢
  • 2017-08-30
  • 1970-01-01
  • 2019-04-20
  • 2020-03-08
  • 2019-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多