【问题标题】:Custom function to mutate a new column for row means using starts_with()为行改变新列的自定义函数意味着使用starts_with()
【发布时间】:2019-12-23 19:49:26
【问题描述】:

我有一个数据框,我想为其创建行均值的列。应该为数据中的一组列计算每一行平均列。它们是相互关联的。我可以使用 dplyr 的starts_with() 区分列组。由于我有几组列来计算行均值,因此我想构建一个函数来完成它。由于某种原因,我无法让它工作。

数据

df <- data.frame("europe_paris" = 1:10, 
                 "europe_london" = 11:20, 
                 "europe_rome" = 21:30,
                 "asia_bangkok" = 31:40,
                 "asia_tokyo" = 41:50,
                 "asia_kathmandu" = 51:60)
set.seed(123)
df <- as.data.frame(lapply(df, function(cc) cc[ sample(c(TRUE, NA),
                                                 prob = c(0.70, 0.30),
                                                 size = length(cc), 
                                                 replace = TRUE) ]))

df

   europe_paris europe_london europe_rome asia_bangkok asia_tokyo asia_kathmandu
1             1            NA          NA           NA         41             51
2            NA            12          22           NA         42             52
3             3            13          23           33         43             NA
4            NA            14          NA           NA         44             54
5            NA            15          25           35         45             55
6             6            NA          NA           36         46             56
7             7            17          27           NA         47             57
8            NA            18          28           38         48             NA
9             9            19          29           39         49             NA
10           10            NA          30           40         NA             60

我想为每个大陆跨城市的行均值创建一个新列。亚洲城市一栏,欧洲一栏。该函数的每次运行都将输入一个大陆的名称,以指导选择哪些列。

我尝试构建函数

此尝试基于this answer

continent_mean <- 
  function(continent)  {
  df %>%
  select(starts_with(as.character(continent))) %>%
  mutate(., (!!as.name(continent)) == rowMeans(., na.rm = TRUE))
}

但是,运行此代码会导致一种奇怪的行为,因为它似乎返回相同的数据集,只有根据 starts_with() 选择的列,但它不会为行均值生成新列。

continent_mean("asia")

   asia_bangkok asia_tokyo asia_kathmandu
1            31         41             51
2            32         42             52
3            33         43             53
4            34         44             54
5            35         45             55
6            36         46             56
7            37         47             57
8            38         48             58
9            39         49             59
10           40         50             60

我在这里缺少什么?我认为这可能是由于mutate() 中的== 而不是=,但是单个= 会引发错误,因此它似乎也不是解决方案。

谢谢!

【问题讨论】:

    标签: r function dplyr


    【解决方案1】:

    我们可以使用quo_name来分配列名

    library(dplyr)
    library(rlang)
    
    continent_mean <- function(df, continent)  {
        df %>%
          select(starts_with(continent)) %>%
          mutate(!!quo_name(continent) := rowMeans(., na.rm = TRUE))
    }
    
    continent_mean(df, "asia")
    
    
    #   asia_bangkok asia_tokyo asia_kathmandu asia
    #1            NA         41             51   46
    #2            NA         42             52   47
    #3            33         43             NA   38
    #4            NA         44             54   49
    #5            35         45             55   45
    #6            36         46             56   46
    #7            NA         47             57   52
    #8            38         48             NA   43
    #9            39         49             NA   44
    #10           40         NA             60   50
    

    使用base R,我们可以做类似的事情

    continent_mean <- function(df, continent)  {
         df1 <- df[startsWith(names(df), "asia")]
         df1[continent] <- rowMeans(df1, na.rm = TRUE)
         df1
    }
    

    如果我们想将所有大陆的rowMeans 放在一起,我们可以使用split.default

    sapply(split.default(df, sub("_.*", "", names(df))), rowMeans, na.rm = TRUE)
    
    #      asia europe
    # [1,]   46      1
    # [2,]   47     17
    # [3,]   38     13
    # [4,]   49     14
    # [5,]   45     20
    # [6,]   46      6
    # [7,]   52     17
    # [8,]   43     23
    # [9,]   44     19
    #[10,]   50     20
    

    【讨论】:

    • 感谢您以多种方式回答。但是,对于您提出的第一种方法,我得到的输出与您的不同。我从字面上将您的代码复制并粘贴到我的 R 会话中,但得到了其他东西。事实上,我得到了与我在帖子中展示的相同的输出。用 dput() 编码,这就是我得到的:structure(list(asia_bangkok = c(31L, 32L, 33L, 34L, 35L, 36L, NA, 38L, 39L, 40L), asia_tokyo = c(41L, 42L, 43L, NA, 45L, NA, NA, 48L, 49L, 50L), asia_kathmandu = c(NA, 52L, 53L, NA, NA, 56L, 57L, NA, 59L, 60L)), class = "data.frame", row.names = c(NA, -10L))。怎么会?
    • 奇怪。我在 RStudio 云上尝试了代码,并得到了与 Ronak 相同的输出。所以问题出在我的本地系统上。
    • @Emman 您在本地系统和云端有什么R.version?检查包版本以及dplyrrlang
    • 我发现了问题。 mutate()plyrdplyr 库掩盖。指定dplyr::mutate(!!quo_name(continent) := rowMeans(., na.rm = TRUE)) 解决了它,我现在在我的本地系统上也得到了与你和 RStudio-Cloud 相同的输出。
    猜你喜欢
    • 2013-09-03
    • 2020-06-15
    • 1970-01-01
    • 2023-03-30
    • 2016-10-09
    • 1970-01-01
    • 2010-09-14
    • 1970-01-01
    相关资源
    最近更新 更多