You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用purrr包编写可应用于数据集列的自定义函数

解决purrr::map()调用自定义函数时的因子参数报错问题

问题场景

需要将自定义函数应用于数据集的一组列并返回列表,lapply()可正常实现,但使用purrr包的map()时遭遇报错。

示例数据

df <- data.frame(variableA = factor(sample(x = c("lessThan", "moreThan"),
                                           size = 20,
                                           replace = T,
                                           prob = c(0.5, 0.5))),
                 variableB = factor(sample(x = c("lessThan", "moreThan"),
                                           size = 20,
                                           replace = T,
                                           prob = c(0.2, 0.8))),
                 variableC = factor(sample(x = c("lessThan", "moreThan"),
                                           size = 20,
                                           replace = T,
                                           prob = c(0.4, 0.6)))) 

自定义函数

该函数接受字符串形式的变量名,返回各水平比例的DataFrame(已修正原代码中管道符的笔误):

countMoreLessFunct <- function(data, var) {
  data %>%
    group_by(.data[[var]]) %>%
      summarise(count = n()) %>%
        ungroup() %>%
          mutate(tot = sum(count),
                 perc = round(x = count/tot*100,
                              digits = 2))
}

报错代码及信息

直接对df调用map()时出现错误:

df %>%
  map(.f = ~countMoreLessFunct(df, .x))

错误信息:

# Error in `map()`:
#   ℹ In index: 1.
#   ℹ With name: variableA.
# Caused by error in `group_by()`:
#   ℹ In argument: `.data[[structure(c(1L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 2L, 2L, `." 
# Caused by error in `.data[[<fct>]]`:
#   ! Must subset the data pronoun with a string, not a <factor> object. 

错误原因

直接对data.frame使用map()时,map()会迭代每一列的实际值(即因子向量),而不是列名(字符串)。但自定义函数countMoreLessFunct要求传入的var是字符串形式的列名,因此传入因子对象后,.data[[var]]无法识别,导致报错。

解决方案

方法1:迭代列名字符串向量

直接生成列名的字符串向量,用map()迭代该向量:

library(purrr)
library(dplyr)

names(df) %>% 
  map(~countMoreLessFunct(df, .x))

方法2:使用imap()获取列名

imap()会同时传递每一列的值和对应的列名,我们可以用.y参数提取列名传入函数,此方法会保留列表元素的名称(对应原列名):

imap(df, ~countMoreLessFunct(df, .y))

可选:调整自定义函数兼容多种输入

如果希望函数既能接受字符串列名,也能直接接受列向量,可以修改函数使用dplyr的非标准求值语法:

countMoreLessFunct <- function(data, var) {
  var <- rlang::ensym(var)
  data %>%
    group_by({{var}}) %>%
      summarise(count = n()) %>%
        ungroup() %>%
          mutate(tot = sum(count),
                 perc = round(x = count/tot*100,
                              digits = 2))
}

# 此时两种调用方式都可行
countMoreLessFunct(df, variableA) # 直接传列名
countMoreLessFunct(df, "variableA") # 传字符串
# 配合map的话,依然需要迭代列名
names(df) %>% map(~countMoreLessFunct(df, .x))

内容的提问来源于stack exchange,提问作者llewmills

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 18:15:13