【问题标题】:How to apply functions sequentially with purrr and pipes如何使用 purrr 和管道顺序应用函数
【发布时间】:2019-10-26 12:51:46
【问题描述】:

我正在为 purrr 包而苦苦挣扎。

我正在尝试将函数 is.factor 应用于数据框,然后将 fct_count 应用于那些是因子的列。

我尝试了modify_ifsummarise_if 的一些变体。我想我在调用前一个对象时错误地使用了点 (.)。

(关于 purrr 的指南,如果您有链接,点将非常有用)。

例如,

df <- data.frame(f1 = c("men", "woman", "men", "men"), 
                 f2 = c("high", "low", "low", "low"), 
                 n1 = c(1, 3, 3, 6))

然后

map(df, is.factor)

如果我使用

map_if(df, is.factor, forcats::fct_count)

我得到了每个变量的结果,而不仅仅是因子。

我认为这是一个很简单的问题,稍微了解点(.)就可以解决。

提前致谢 :)

【问题讨论】:

  • 您的预期输出是什么?我怀疑这是因为stringsAsFactorsTRUE。否则,结果对我来说似乎很清楚。
  • 试试df %&gt;% mutate_if(is.factor, list(~list( fct_count(.)))) %&gt;% unnest
  • 感谢您的帮助。 Akrun,你介意参考一个网站,在那里我可以了解更多关于 purrr 包的信息(如何使用点 ~list、unnest 等。在此先感谢 :)

标签: r dictionary iteration purrr


【解决方案1】:

问题是map_if 也返回未修改的列。因此,当 OP 尝试代码时(重复与 OP 中相同的代码只是为了显示)

map_if(df, is.factor, forcats::fct_count)
#$f1
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 men       3
#2 woman     1

#$f2
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 high      1
#2 low       3

#$n1
#[1] 1 3 3 6  ### it is the same column value unchanged

在这里,我们可以指定.elsediscard NULL 元素。因此,如果我们指定其他列返回NULL,然后使用discardNULL 元素,那么这将是一个list 的因子计数。

library(tidyverse)
map_if(df, is.factor, forcats::fct_count, .else = ~ NULL) %>%
       discard(is.null)
#$f1
## A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 men       3
#2 woman     1

#$f2
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 high      1
#2 low       3

或者另一个选项是summarise_if,并将输出放在list

df %>% 
      summarise_if(is.factor, list(~ list(fct_count(.)))) %>%
      unclass

或者另一种选择是将gather 转换为“长”格式,然后count 一次

gather(df, key, val, f1:f2) %>% 
        dplyr::count(key, val)

或者这可以通过来自base Rlapply 来完成

lapply(df[sapply(df, is.factor)], fct_count)

或者只使用base R

lapply(df[sapply(df, is.factor)], table)

或者结果可以用不同的方式表示

table(names(df)[1:2][col(df[1:2])], unlist(df[1:2]))

【讨论】:

  • 我认为OP 的代码是正确的,只是他们假设已进行了修改:modify_if() only modifies the elements of x that satisfy a predicate and leaves the others unchanged. 我认为他们应该首先使用keep
  • @NelsonGon 是的,你是对的。 map_if 使其他列保持不变。我假设如果 OP 只想返回这些列,而不是整个数据集
  • ``` map_if(df, is.factor, forcats::fct_count, .else = ~ NULL) %>% discard(is.null) ``` @akrun 这个效果很好,而且我可以将它用于未来的代码。感谢您的帮助:)
【解决方案2】:

map_if/modify_if 的问题在于它仅将函数应用于满足谓词函数的列,其余列按原样返回。

因此,当您尝试时

library(tidyverse)  
map_if(df, is.factor, forcats::fct_count)

#$f1
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 men       3
#2 woman     1

#$f2
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 high      1
#2 low       3

#$n1
#[1] 1 3 3 6

fct_count 应用于作为因子的列f1f2,并按原样返回列n1。如果您只想在输出中获取因子列,一种方法是先 select 他们然后应用函数

df %>%
  select_if(is.factor) %>%
  map(forcats::fct_count)

#$f1
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 men       3
#2 woman     1

#$f2
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 high      1
#2 low       3

【讨论】:

  • 是的,你是对的 Ronak。我可以通过更多搜索找到这个解决方案。感谢您的帮助 =)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-03
  • 1970-01-01
  • 2019-12-20
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
相关资源
最近更新 更多