【问题标题】:Using lists to simplify code in R使用列表来简化 R 中的代码
【发布时间】:2018-10-24 13:17:40
【问题描述】:

背景:

大家好,

我希望你能帮助我将我的理解和代码提升到一个新的水平。我试图围绕列表、它们的好处以及使用它们来减少冗余代码。尽管我在网上阅读了有关列表和申请家庭的信息,但我仍然无法理解如何在我的日常工作中实施。

这是一种我认为可以大大简化的情况 - 这是我经常编写的代码类型,我希望用更简洁的格式替换它。

示例:

让我们假设整个 mtcars 数据是针对单个观察年份的——比如 2018 年。我们还假设我们每年都有数据可以追溯到 2000 年。所以现在有“18”个 mtcars data.frames 有一个年份列表示这一年,我们将 18 个观察值逐行绑定到一个 data.frame 中。这是我现在正在使用的数据类型的一个示例。观察按年份分开。

data <- mtcars %>%
group_by(date) %>%
  mutate(rank = dense_rank(desc(mpg))
         ))

我想简化的数据操作:

  • 过滤:我想按不同的mpg等级过滤给定年份的所有内容

    数据 %>% 过滤器(齿轮 == 4,日期 == '2005')%>% 过滤器(排名 %in% c(1:5))

    数据 %>% 过滤器(齿轮 == 4,日期 == '2005')%>% 过滤器(排名 %in% c(6:10))

    数据 %>% 过滤器(齿轮 == 4,日期 == '2005')%>% 过滤器(排名 %in% c(11:15))

简化上述冗余代码块的最佳方法是什么?

例如,我想利用seq 函数并按照以下方式做一些事情:

    data %>% 
filter(gear == 4, date == '2005') %>%
filter(rank %in% seq(1, 100, by = 5))

并将每个排名组的输出存储到一个列表中,然后在 ggplot 中绘制所有这些列表。

任何帮助或建议将不胜感激,我正在努力改进我的游戏。

【问题讨论】:

  • 您要问的问题非常广泛,即,一般而言,我如何使我的代码减少冗余?在过滤的特定情况下,我的策略是创建可以连接到主要数据帧的“帮助”数据帧。例如,您可能有一个包含yearminmax 列的数据框,按“年”将其连接到mtcars,然后filter(mtcars, year &gt;= min &amp; year &lt;= max)
  • 您应该寻找拆分而不是过滤的函数。

标签: r list vector functional-programming programmatically


【解决方案1】:

学习以整洁的方式使用列表和列表列可能有点复杂。我非常推荐 Jenny Bryan 的 purrr tutorial。在这里,您试图避免对yeargearrank 的不同值多次执行filter 行。有几个步骤:

  1. 弄清楚如何获得所需值的所有组合。我们在这里使用purrr::cross_df 执行此操作,这是获取变量组合的一种非常方便的方法。
  2. 实际运行每个组合的操作。因为我们的数据现在已经很好地设置为每行都是一组输入,所以我们可以使用pmap 将每个过滤后的数据集存储为列表元素。根据我们想要的绘图,我们可以使用其他工具(例如 unnest)将数据实际转换为我们想要绘图的格式。

我希望这可以说明,一般来说,如果你意识到自己做了太多次,基本上有两个步骤;创建一个或多个可以迭代的列表,并使用map 函数将您想要的操作应用于每个列表元素。

library(tidyverse)
data <- mtcars %>%
  bind_rows(
    mtcars %>% mutate(year = 2005),
    mtcars %>% mutate(year = 2006)
    ) %>% 
  group_by(year) %>%
  mutate(rank = dense_rank(desc(mpg)))

combos <- cross_df(list(
  year = 2005:2006,
  gear = 3:5,
  start = seq(1, 100, by = 5)
  ))

combos %>%
  mutate(
    rank_range = map(start, ~ .x:(.x + 4)),
    filtered = pmap(
      .l = list(year, gear, rank_range),
      .f = ~ data %>%
        filter(gear == ..2, year == ..1) %>%
        filter(rank %in% ..3)
        )
    )
#> # A tibble: 120 x 5
#>     year  gear start rank_range filtered         
#>    <int> <int> <dbl> <list>     <list>           
#>  1  2005     3     1 <int [5]>  <tibble [0 x 13]>
#>  2  2006     3     1 <int [5]>  <tibble [0 x 13]>
#>  3  2005     4     1 <int [5]>  <tibble [4 x 13]>
#>  4  2006     4     1 <int [5]>  <tibble [4 x 13]>
#>  5  2005     5     1 <int [5]>  <tibble [2 x 13]>
#>  6  2006     5     1 <int [5]>  <tibble [2 x 13]>
#>  7  2005     3     6 <int [5]>  <tibble [2 x 13]>
#>  8  2006     3     6 <int [5]>  <tibble [2 x 13]>
#>  9  2005     4     6 <int [5]>  <tibble [6 x 13]>
#> 10  2006     4     6 <int [5]>  <tibble [6 x 13]>
#> # ... with 110 more rows

reprex package (v0.2.0) 于 2018 年 5 月 14 日创建。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-20
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 2018-12-09
    • 2023-01-22
    • 2013-04-15
    相关资源
    最近更新 更多