【问题标题】:dplyr rowwise by some columnsdplyr 按行逐列
【发布时间】:2016-07-31 01:47:12
【问题描述】:

对某些列应用函数rowwisedplyr 方法是什么。例如,我想抓取所有 V, 列并根据行总和将它们转换为百分比。我展示了如何在基地中做到这一点。在 dplyr 链中呢?很高兴也能以 data.table 的形式看到(尽管这里优先考虑 dplyr 解决方案)。

x <- data.frame(A=LETTERS[1:5], as.data.frame(matrix(sample(0:5, 25, T), ncol=5)))

data.frame(x[1], x[-1]/rowSums(x[-1]))


##   A        V1        V2        V3         V4         V5
## 1 A 0.1428571 0.2142857 0.2142857 0.35714286 0.07142857
## 2 B 0.2000000 0.2000000 0.1500000 0.20000000 0.25000000
## 3 C 0.3571429 0.2857143 0.0000000 0.07142857 0.28571429
## 4 D 0.1904762 0.2380952 0.1904762 0.23809524 0.14285714
## 5 E 0.2000000 0.2500000 0.1500000 0.25000000 0.15000000

library(dplyr)

props <- function(x) round(x/sum(x), 2)

# does not work
x %>%
    rowwise()
    mutate(props(matches("^.{2}$")))

【问题讨论】:

  • 可能是x %&gt;% rowwise() %&gt;% select(matches("^.{2}$")) %&gt;% props %&gt;% cbind(x[1], .)?下半场虽然不是真正的 dplyrey
  • 我不是 dplyr 专家,但你不能在 dplyr 中也使用rowSums 吗?像props &lt;- function(x, y) round(x/y, 2) ; x %&gt;% mutate(Total = rowSums(.[-1])) %&gt;% mutate_each(funs(./Total), -c(A, Total)) 这样的东西。尽管rowSumsrowwise 都应该是低效的。如果你没有NAs,我会选择Reduce(`+`, .[-1]))
  • @DavidArenburg Nice 你能不能回答一下。它有效。
  • @Frank 真的不需要。我将删除,尽管它允许任何人只运行代码而无需键入库等来获取 dplyr。
  • SO dplyr 中 hadley 附近的“已知 data.table 人”回答排行榜 :) stackoverflow.com/tags/dplyr/topusers

标签: r data.table dplyr


【解决方案1】:

在data.table中,你可以这样做

library(data.table)
setDT(x)

x[, grep("^V",names(DT)) := .SD/Reduce(`+`, .SD), .SDcols = V1:V5]

   A         V1        V2        V3         V4         V5
1: A 0.28571429 0.0000000 0.2857143 0.07142857 0.35714286
2: B 0.23076923 0.2307692 0.3076923 0.15384615 0.07692308
3: C 0.44444444 0.0000000 0.4444444 0.00000000 0.11111111
4: D 0.07142857 0.3571429 0.1428571 0.07142857 0.35714286
5: E 0.00000000 0.2222222 0.3333333 0.44444444 0.00000000

要在忽略 NA 值的情况下计算分母,我猜 rowSums 是一种选择,尽管它会将 .SD 强制转换为矩阵作为中间步骤。

【讨论】:

  • 没关系。 Reduce(`+`,... 不是我发明的。我只是想知道这不是骗局吗?
  • stackoverflow.com/questions/35306500/… 是相关的,但并不完全相同。
  • @DavidArenburg 看来应该是骗子,但我找不到标题明显的人。
  • @thelatemail 我们正在为some time now 做这些Reduce(`+`, .SD)。这是阿克伦in 2014
  • 没有意识到您可以在 LHS 上传递 := 的列号...我会使用 value = TRUE
【解决方案2】:

您可以将spreadgather 结合起来得到以下单个管道:

x <- data.frame(A=LETTERS[1:5], as.data.frame(matrix(sample(0:5, 25, T), ncol=5)))

y <- x %>% 
        gather(V, val, -A) %>% 
        group_by(A) %>% 
        mutate(perc = val / sum(val)) %>% 
        select(-val) %>%
        spread(V, perc)

使用tidy data,很容易获得任何分组求和(行、列或任何嵌套索引级别)并计算百分比。 spreadgather 将让您在输入数据格式之间进行转换。

【讨论】:

  • 啊,非常有道理。这是一个“为什么我没有想到那一刻”。
  • 像这样按行分组,我猜这会随着数据的增长而迅速放缓
  • @eddi 我还没有在大数据上测试过这个。 dplyr 可能不是最好的方法。我怀疑它会比 OP 显示的 data.frame 重新缩放 rowSums 慢。在整洁的数据格式中,总是可以在做group_by(A)之前先做一个arrange(A),这样每组的数据就会被顺序处理。
【解决方案3】:

另一个“tidyverse”解决方案是在mutate 中使用select。例如

library(tidyverse)

x <- data.frame(A=LETTERS[1:5], as.data.frame(matrix(sample(0:5, 25, T), ncol=5)))

x %>% 
  mutate(row_counts = select_if(., is.numeric) %>% rowSums()) %>% 
  mutate_at(vars(contains("V")), funs(./row_counts)) %>% 
  select(-row_counts)
#>   A        V1         V2        V3        V4        V5
#> 1 A 0.0000000 0.14285714 0.1428571 0.5714286 0.1428571
#> 2 B 0.0000000 0.62500000 0.1250000 0.1250000 0.1250000
#> 3 C 0.2222222 0.11111111 0.2222222 0.1111111 0.3333333
#> 4 D 0.3000000 0.50000000 0.1000000 0.1000000 0.0000000
#> 5 E 0.3333333 0.06666667 0.1333333 0.3333333 0.1333333

reprex package (v0.2.1) 于 2019 年 2 月 16 日创建

【讨论】:

    猜你喜欢
    • 2018-05-15
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-09
    • 1970-01-01
    相关资源
    最近更新 更多