dplyr 1.0.0 之 rowwise

作者: 热衷组培的二货潜 | 来源:发表于2020-06-06 22:55 被阅读0次

    dplyr 1.0.0 之 rowwise

    加载包

    library(tidyverse, warn.conflicts = F)
    

    <br />在 R 中 dplyr 通常是对列进行操作,然而对于行处理方面还是b比较困难,本节我们将学习通过 rowwise()函数来对数据进行行处理,常与 c_across() 连用。<br />
    <br />本节中列举了三个常见的案例:<br />

    • 行水平的计算(比如,xyz 的平均值)
    • 使用不同的参数调用同一个函数
    • 对列表列进行操作

    <br />当然这些问题我们可以通过类似 for 等循环来进行操作,但是我们可以通过管道的形式进行更便捷的操作,这里作者有一句经典的话:<br />

    Of course, someone has to write loops. It doesn’t have to be you. — Jenny Bryan

    <a name="a6d31b10"></a>

    实战:

    <br />rowwise 按行来进行分组,和 group_by() 函数一样,并不会改变数据得内容,仅仅是进行分组:<br />

    df <- tibble(x = 1:2, y = 3:4, z = 5:6)
    df %>% rowwise()
    
    # 计算的是数据中所有的数值的平均值
    df %>% mutate(m = mean(c(x, y, z)))
    
    # 计算每一列的平均值
    df %>% mutate(across(everything(), ~mean(.x, na.rm = T)))
    
    # 计算的是每一行的平均值
    df %>% rowwise() %>% mutate(m = mean(c(x, y, z)))
    

    <a name="c5649d16"></a>

    rowwise() 与 summarise() 函数连用

    df <- tibble(name = c("Mara", "Hadley"), x = 1:2, y = 3:4, z = 5:6)
    
    # 结果仅仅只有值
    df %>% 
      rowwise() %>% 
      summarise(m = mean(c(x, y, z)))
    
    # 可以通过加上需要处理的行作为 summarise() 的行名,可以使用 `rowwise(name)`,保留 `name` 列
    df %>% 
      rowwise(name) %>% 
      summarise(m = mean(c(x, y, z)))
    

    <a name="e2c5cace"></a>

    每一行进行统计

    df <- tibble(id = 1:6, w = 10:15, x = 20:25, y = 30:35, z = 40:45)
    df
    
    # 使用 `rowwise` 对数据进行行分组 
    rf <- df %>% rowwise(id)
    
    rf %>% mutate(total = sum(c(w, x, y, z)))
    rf %>% summarise(total = sum(c(w, x, y, z)))
    

    <a name="b2d1310f"></a>

    多列 c_across() 联合操作

    rf %>% mutate(total = sum(c_across(w:z)))
    
    
    rf %>% mutate(total = sum(c_across(where(is.numeric))))
    

    <a name="c275761c"></a>

    rowwise()c_across()across() 连用

    ungroup() 取消分组,这里表示取消按照行进行分组

    rf %>% 
      mutate(total = sum(c_across(w:z))) %>% 
      ungroup() %>% 
      mutate(across(w:z, ~ . / total))
    

    <a name="b09a9c97"></a>

    行处理函数总结:rowSums()rowMeans()

    内置行处理函数更快,对行进行操作,没有分成行、然后统计,最后连接到一起。

    df %>% mutate(total = rowSums(across(where(is.numeric))))
    
    df %>% mutate(mean = rowMeans(across(where(is.numeric))))
    

    <a name="ec71b358"></a>

    列表-列

    df <- tibble(
      x = list(1, 2:3, 4:6)
    )
    
    # 计算列表中向量的个数,返回的是列的长度,而不是列表中每一个向量的长度
    df %>% mutate(l = length(x))
    
    # 计算列表中单个向量的长度
    df %>% mutate(l = lengths(x))
    
    # 或者利用 sapply()、vapply() map() 函数功能实现
    df %>% mutate(l = sapply(x, length))
    
    df %>% mutate(l = purrr::map_int(x, length))
    
    # 我们可以通过 rowwise() 函数来实现
    df %>% 
      rowwise() %>% 
      mutate(l = length(x))
    

    <a name="5d04e51c"></a>

    Subsetting:取子集

    df <- tibble(g = 1:2, y = list(1:3, "a"))
    gf <- df %>% group_by(g)
    rf <- df %>% rowwise(g)
    
    gf %>% mutate(type = typeof(y), length = length(y))
    
    rf %>% mutate(type = typeof(y), length = length(y))
    

    <a name="2c6a15d0"></a>

    通过 for 循环来计算列表中子向量的长度应该取 [[]] 而非 []

    # grouped
    out1 <- integer(2)
    for (i in 1:2) {
      out1[[i]] <- length(df$y[i])
    }
    out1
    
    # rowwise
    out2 <- integer(2)
    for (i in 1:2) {
      out2[[i]] <- length(df$y[[i]])
    }
    out2
    

    <a name="709da5d0"></a>

    group_by()rowwise() 分组后添加新的列时,应该注意以下

    gf %>% mutate(y2 = y)
    
    # 报错,由于 rowwise 的结果是列表中子向量的值,长度不一致
    
    # rf %>% mutate(y2 = y)
    
    # 通过 `list()` 函数将其存储为一个 list()
    
    rf %>% mutate(y2 = list(y))
    

    <a name="9c427e2d"></a>

    Modelling:建模(无脑运行的。)

    nest_by() 分组存储为一个 list

    by_cyl <- mtcars %>% nest_by(cyl)
    by_cyl
    

    <a name="2524ce58"></a>

    按行线性建模

    mods <- by_cyl %>% mutate(mod = list(lm(mpg ~ wt, data = data)))
    mods
    
    mods <- mods %>% mutate(pred = list(predict(mod, data)))
    mods
    

    <a name="5105b123"></a>

    summarise() 函数进行统计

    mods %>% summarise(rmse = sqrt(mean((pred - data$mpg) ^ 2)))
    
    mods %>% summarise(rsq = summary(mod)$r.squared)
    
    mods %>% summarise(broom::glance(mod))
    
    
    mods %>% summarise(broom::tidy(mod))
    

    <a name="35610ed3"></a>

    重复的函数调用:按行传入变量参数

    <br />rowwise() 不仅适用于返回长度为 1 的向量的函数; 如果结果是一个列表,它可以与任何函数一起连用。这意味着 rowwise()mutate() 提供了一种优雅的方法,可以多次使用不同的参数调用函数,将输出存储在输入旁边。<br />

    一定要用 list() 函数来将命令括起来,比如 list(runif(n, min, max)) 而非 runif(n, min, max)

    df <- tribble(
      ~ n, ~ min, ~ max,
        1,     0,     1,
        2,    10,   100,
        3,   100,  1000,
    )
    
    df %>% 
      rowwise() %>% 
      mutate(data = list(runif(n, min, max)))
    
    # 会报错
    df %>% 
      rowwise() %>% 
      mutate(data = runif(n, min, max))
    

    <a name="194c5bcf"></a>

    两两多重组合:tidyr::expand_grid() 函数

    # 这里就会得到  3*3 九种结果
    df <- expand.grid(mean = c(-1, 0, 1), sd = c(1, 10, 100))
    
    df %>% 
      rowwise() %>% 
      mutate(data = list(rnorm(10, mean, sd)))
    

    <a name="bc13740f"></a>

    各种功能:结合 do.call()

    df <- tribble(
       ~rng,     ~params,
       "runif",  list(n = 10), 
       "rnorm",  list(n = 20),
       "rpois",  list(n = 10, lambda = 5),
    ) %>%
      rowwise()
    
    df %>% 
      mutate(data = list(do.call(rng, params)))
    

    <a name="772ab8dd"></a>

    以前的操作

    作者建议使用 purrrmap() 函数执行行操作,但是又会增加额外学习。

    相关文章

      网友评论

        本文标题:dplyr 1.0.0 之 rowwise

        本文链接:https://www.haomeiwen.com/subject/ratqtktx.html