Kon*_*rad 5 nested r dplyr tibble
给定嵌套数据,我想对across任意选择的列应用一个简单的函数。使用across我想迭代传递给函数一个参数的列的选择,并保持第二个参数不变。
# Using across within nested data frame\n\n# Gapminder data from gapminder package\nlibrary("tidyverse")\ndata("gapminder", package = "gapminder")\n\n# Sample function\nsample_function <- function(.data, var_a, var_b) {\n var_a <- enquo(var_a)\n var_b <- enquo(var_b)\n .data %>%\n mutate(some_res = log(!!var_a) + !!var_b) %>%\n pull(some_res)\n}\n\n\n# Basic example, not working\ngapminder %>%\n group_by(country, continent) %>%\n nest() %>%\n mutate(sample_res = map(\n .x = data,\n .f = across(\n .cols = vars(year, lifeExp, pop),\n .fns = ~ sample_function(var_a = .x),\n var_b = gdpPercap\n )\n )) %>%\n unnest(sample_res)\nRun Code Online (Sandbox Code Playgroud)\n\n该示例失败并出现以下错误:
\n\n\n\n\n错误:
\nmutate()输入有问题sample_res。x 必须使用有效下标向量对列进行子集化。x 下标类型错误\nquosures。\xe2\x84\xb9 必须是数字或字符。\xe2\x84\xb9 输入sample_res为\nmap(...)。\xe2\x84\xb9 错误发生在第 1 组:国家=“阿富汗”,\n 大陆=“亚洲”。运行rlang::last_error()以查看错误发生的位置。
我可以迭代选定的列,始终在var_a. 在这种情况下,值反映year和变量。lifeExpgdpPercap
gapminder %>%\n group_by(country, continent) %>%\n nest() %>%\n mutate(\n res_year = map(.x = data, \n .f = sample_function, var_a = year, var_b = gdpPercap),\n res_lifeExp = map(.x = data, \n .f = sample_function, var_a = lifeExp, \n var_b = gdpPercap),\n res_pop = map(.x = data, \n .f = sample_function, var_a = pop, var_b = gdpPercap)\n )\nRun Code Online (Sandbox Code Playgroud)\n\n在所需结果中获得的解决方案相当不切实际且容易出错,因为会强制为每个变量添加新行。我想找到 using 的组合across,map这样我只需将变量添加到 即可运行映射函数的不同变体across。
最终更新(使用nest_by& across)
受到@Brunos回答的启发,我修改了我的方法以使用nest_by/rowwise代替map(我猜这是争论嵌套小标题的新推荐方法)。
我原来的答案的结果可以很容易地重现nest_by:
gapminder %>%\n nest_by(country, continent) %>%\n mutate(sample_res = list(transmute(data,\n across(c(year, lifeExp, pop),\n ~ sample_function(data, var_a = .x, var_b = gdpPercap))\n ))\n ) \nRun Code Online (Sandbox Code Playgroud)\n\n然而,它返回一个包含 s 的列表列tibble。如果输出是法线向量,我们可以删除sample_res = list()新的列,并将新列添加到现有的小标题中。但是,在此示例中,每个新列的输出是包含向量的列表列。我未能在一次调用中产生此输出mutate(across(...))。
不过,可以使用unnest然后再次调用来summarise(across(...))完成工作。
gapminder %>%\n nest_by(country, continent) %>%\n mutate(sample_res = list(transmute(data,\n across(c(year, lifeExp, pop),\n ~ sample_function(data, var_a = .x, var_b = gdpPercap))\n ))\n ) %>% \n unnest(cols = sample_res) %>%\n summarise(across(c(year, lifeExp, pop), list, .names = "res_{col}"))\nRun Code Online (Sandbox Code Playgroud)\n\n
\n原始答案(使用group_by, nest, map& across)
您sample_function在across通话中指定错误。它应该是
function(x) sample_function(.x, var_a = x, var_b = gdpPercap)\nRun Code Online (Sandbox Code Playgroud)\n\n代替
\n\n~ sample_function(var_a = .x),\n var_b = gdpPercap\nRun Code Online (Sandbox Code Playgroud)\n\n由于您正在嵌套map和mutate(across(...)),我更喜欢至少有一个“正常”匿名函数而不是 lamda~表示法。否则,事情可能会因为两个.xs 而变得混乱。
进一步across应该在其内部单独调用mutate。
这应该有效:
\n\n\n\ngapminder %>%\n nest_by(country, continent) %>%\n mutate(sample_res = list(transmute(data,\n across(c(year, lifeExp, pop),\n ~ sample_function(data, var_a = .x, var_b = gdpPercap))\n ))\n ) \nRun Code Online (Sandbox Code Playgroud)\n\n由reprex 包(v0.3.0)于 2020-06-03 创建
\n\n当使用自定义函数在列表列中map循环时,在循环之外构建第一个版本非常有帮助。tibbles
gapminder %>%\n nest_by(country, continent) %>%\n mutate(sample_res = list(transmute(data,\n across(c(year, lifeExp, pop),\n ~ sample_function(data, var_a = .x, var_b = gdpPercap))\n ))\n ) %>% \n unnest(cols = sample_res) %>%\n summarise(across(c(year, lifeExp, pop), list, .names = "res_{col}"))\nRun Code Online (Sandbox Code Playgroud)\n\n一旦成功,最后一步就是将要循环的对象替换为.x.
另一种方法(原始答案的一部分)
\n\n另一种方法是重写您的原始内容sample_function并将其包含across在您的mutate通话中。我们可以让它采用将传递给 的变量名称的字符串向量across。我可能更喜欢这种方法,因为它更灵活。现在,您可以有另一个列表列,其中包含不同数据子集的不同变量名称,并使用 .循环遍历它们和数据列map2。
function(x) sample_function(.x, var_a = x, var_b = gdpPercap)\nRun Code Online (Sandbox Code Playgroud)\n\n由reprex 包(v0.3.0)于 2020-06-04 创建
\n\n添加(到原始答案)
\n\n正如@Bruno指出的,上面的方法不是OP指定的格式,这里是一个基于我上面的第二种方法构建的替代解决方案,它应该产生所需的输出。
\n\n\n\n~ sample_function(var_a = .x),\n var_b = gdpPercap\nRun Code Online (Sandbox Code Playgroud)\n\n由reprex 包(v0.3.0)于 2020-06-04 创建
\n