R / tidyverse:计算各行的标准偏差

时间:2019-03-24 18:29:34

标签: r dplyr statistics

说我有以下数据:

colA <- c("SampA", "SampB", "SampC")
colB <- c(21, 20, 30)
colC <- c(15, 14, 12)
colD <- c(10, 22, 18)
df <- data.frame(colA, colB, colC, colD)
df
#    colA colB colC colD
# 1 SampA   21   15   10
# 2 SampB   20   14   22
# 3 SampC   30   12   18

我想获取B-D列中值的行均值和标准差。

我可以按以下方式计算rowMeans:

library(dplyr)
df %>% select(., matches("colB|colC|colD")) %>% mutate(rmeans = rowMeans(.))
#   colB colC colD   rmeans
# 1   21   15   10 15.33333
# 2   20   14   22 18.66667
# 3   30   12   18 20.00000

但是当我尝试使用sd()计算标准差时,会引发错误。

df %>% select(., matches("colB|colC|colD")) %>% mutate(rsds = sapply(., sd(.)))
Error in is.data.frame(x) : 
  (list) object cannot be coerced to type 'double'

所以我的问题是:如何在此处计算标准偏差?

编辑:我尝试sapply()sd()并阅读了第一个答案here

其他编辑:不一定要寻找“整洁”的解决方案(基数R也可以很好地工作)。

7 个答案:

答案 0 :(得分:3)

使用rowSds软件包中的matrixStats尝试(using

library(dplyr)
library(matrixStats)

columns <- c('colB', 'colC', 'colD')

df %>% 
  mutate(Mean= rowMeans(.[columns]), stdev=rowSds(as.matrix(.[columns])))

返回

   colA colB colC colD     Mean    stdev
1 SampA   21   15   10 15.33333 5.507571
2 SampB   20   14   22 18.66667 4.163332
3 SampC   30   12   18 20.00000 9.165151

您的数据

colA <- c("SampA", "SampB", "SampC")
colB <- c(21, 20, 30)
colC <- c(15, 14, 12)
colD <- c(10, 22, 18)
df <- data.frame(colA, colB, colC, colD)
df

答案 1 :(得分:3)

这是使用pmap获取行meansd的另一种方式

library(purrr)
library(dplyr)
library(tidur_
f1 <- function(x) tibble(Mean = mean(x), SD = sd(x))
df %>% 
  # select the numeric columns
  select_if(is.numeric) %>%
  # apply the f1 rowwise to get the mean and sd in transmute
  transmute(out = pmap(.,  ~ f1(c(...)))) %>% 
  # unnest the list column
  unnest %>%
  # bind with the original dataset
  bind_cols(df, .)
#   colA colB colC colD     Mean       SD
#1 SampA   21   15   10 15.33333 5.507571
#2 SampB   20   14   22 18.66667 4.163332
#3 SampC   30   12   18 20.00000 9.165151

答案 2 :(得分:2)

打包magrittr管道%>%并不是按行处理的好方法。
也许以下是您想要的。

df %>% 
  select(-colA) %>%
  t() %>% as.data.frame() %>%
  summarise_all(sd)
#        V1       V2       V3
#1 5.507571 4.163332 9.165151

答案 3 :(得分:2)

另一种tidyverse方法可能是:

df %>%
 rowid_to_column() %>%
 gather(var, val, -c(colA, rowid)) %>%
 group_by(rowid) %>%
 summarise(rsds = sd(val)) %>%
 left_join(df %>%
            rowid_to_column(), by = c("rowid" = "rowid")) %>%
 select(-rowid)

   rsds colA   colB  colC  colD
  <dbl> <fct> <dbl> <dbl> <dbl>
1  5.51 SampA    21    15    10
2  4.16 SampB    20    14    22
3  9.17 SampC    30    12    18

在这里,首先创建一个行ID。其次,它执行从宽到长的数据转换,但不包括“ colA”和行ID。第三,它按行ID分组并计算标准偏差。最后,它与行ID上的原始df结合起来。

或者,也可以使用rowwise()do()

 df %>% 
 rowwise() %>%
 do(data.frame(., rsds = sd(unlist(.[2:length(.)]))))

  colA   colB  colC  colD  rsds
* <fct> <dbl> <dbl> <dbl> <dbl>
1 SampA    21    15    10  5.51
2 SampB    20    14    22  4.16
3 SampC    30    12    18  9.17

答案 4 :(得分:2)

您可以将pmaprowwise(或按colA分组)与mutate一起使用:

library(tidyverse)
df %>% mutate(sd = pmap(.[-1], ~sd(c(...)))) # same as transform(df, sd = apply(df[-1],1,sd))
#>    colA colB colC colD       sd
#> 1 SampA   21   15   10 5.507571
#> 2 SampB   20   14   22 4.163332
#> 3 SampC   30   12   18 9.165151

df %>% rowwise() %>% mutate(sd = sd(c(colB,colC,colD)))
#> Source: local data frame [3 x 5]
#> Groups: <by row>
#> 
#> # A tibble: 3 x 5
#>   colA   colB  colC  colD    sd
#>   <fct> <dbl> <dbl> <dbl> <dbl>
#> 1 SampA    21    15    10  5.51
#> 2 SampB    20    14    22  4.16
#> 3 SampC    30    12    18  9.17

df %>% group_by(colA) %>% mutate(sd = sd(c(colB,colC,colD)))
#> # A tibble: 3 x 5
#> # Groups:   colA [3]
#>   colA   colB  colC  colD    sd
#>   <fct> <dbl> <dbl> <dbl> <dbl>
#> 1 SampA    21    15    10  5.51
#> 2 SampB    20    14    22  4.16
#> 3 SampC    30    12    18  9.17

答案 5 :(得分:2)

我不确定 dplyrc_across 功能相对于本页上的先前答案有多旧,但这里有一个几乎直接从文档中剪切和粘贴的解决方案dplyr::c_across

df %>% 
  rowwise() %>% 
  mutate(
     mean = mean(c_across(colB:colD)),
     sd = sd(c_across(colB:colD))
  )

# A tibble: 3 x 6
# Rowwise: 
  colA   colB  colC  colD  mean    sd
  <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
1 SampA    21    15    10  15.3  5.51
2 SampB    20    14    22  18.7  4.16
3 SampC    30    12    18  20    9.17

答案 6 :(得分:1)

我看到这篇文章有些陈旧,但是有一些非常复杂的答案,所以我认为我建议一种更简单(更快)的方法。

计算行的平均值很简单,只需使用rowMeans:

rowMeans(df[, c('colB', 'colC', 'colD')])

这是矢量化的,而且速度很快。

没有'rowSd'函数,但是编写它并不难。这是我使用的“行”。

rowVars <- function(x, na.rm=F) {
    # Vectorised version of variance filter
    rowSums((x - rowMeans(x, na.rm=na.rm))^2, na.rm=na.rm) / (ncol(x) - 1)
}

要计算sd:

sqrt(rowVars(df[, c('colB', 'colC', 'colD')]))

重新输入,向量化且快速,如果输入矩阵很大,则可能很重要。