对忽略R中某些值的行的值求和

  • 本文关键字:求和 r dplyr
  • 更新时间 :
  • 英文 :


我有一个关于这个问题的后续内容:对R 中有条件的行的值求和

这是我的数据:

ID <- c("A", "B", "C", "D", "E", "F")
Q1 <- c(0, 1, 7, 9, NA, 3) 
Q2 <- c(0, 3, 2, 2, NA, 3) 
Q3 <- c(0, 0, 7, 9, NA, 3) 
dta <- data.frame(ID, Q1, Q2, Q3) 

我需要对7以下的每个值求和,但在值超过7的行中,我需要对所有低于7的数字求和,忽略超过7的数字。应该保留所有NA的行。结果应该是这样的:

ProxySum
0
4
2
2
NA
9

我已经根据上一篇文章的回复尝试了这个代码:

dta2  <- dta %>% 
rowwise() %>% 
mutate(ProxySum = ifelse(all(c_across(Q1:Q3) < 7), Reduce(`+`, c_across(Q1:Q3)), (ifelse(any(c_across(Q1:Q3) > 7), sum(.[. <  7]), NA))))

但在数字超过7的行中,我得到了所有行和列的总和。我缺少什么?

base:中执行此操作的一种方法

rowSums(dta[, 2:4] * (dta[, 2:4] < 7))
# [1]  0  4  2  2 NA  9

根据@tjebo评论添加解释

  • 使用dta[, 2:4] < 7,您可以生成一个填充有logical值的数据帧,其中TRUEFALSE对应于比7小或大的值。可以在一行中执行,因为此操作是矢量化的
  • 然后,将逻辑数据帧和用原始值填充的数据帧相乘。在引擎盖下,R将logical类型转换为numeric类型,因此逻辑数据集中的所有FALSETRUEs都转换为0s和1s。这意味着,如果原始值小于7,则将其乘以1,否则将乘以0s
  • 由于NA < 7产生NA,然后与NA相乘也会产生NAs,因此保留了原始的NAs
  • 最后一步是对生成的数据帧调用rowSums(),它将对每个特定行的值进行汇总。由于它们中超过7的会变成0,所以您将它们从结果和中排除
  • 在这种情况下,当您想为至少有一个值不是NA的行获取和时,可以在rowSums()调用中使用na.rm = TRUE参数。但是,在这种情况下,对于NAs的行,您将获得0

使用rowSumsdplyr::across的另一个选项:

ID <- LETTERS[1:6]
Q1 <- c(0,1,7,9,NA,3) 
Q2 <- c(0,3,2,2,NA,3) 
Q3 <- c(0,0,7,9,NA,3) 
dta <- data.frame(ID,Q1,Q2,Q3) 
library(dplyr)
dta %>% 
mutate(ProxySum = rowSums(across(Q1:Q3, function(.x) { .x[.x >= 7] <- 0; .x })))
#>   ID Q1 Q2 Q3 ProxySum
#> 1  A  0  0  0        0
#> 2  B  1  3  0        4
#> 3  C  7  2  7        2
#> 4  D  9  2  9        2
#> 5  E NA NA NA       NA
#> 6  F  3  3  3        9

有一个稍微不同的方法吗?先延长数据透视时间,然后按组按条件求和,然后返回数据透视。

在当前版本中,只包含";一些";NA将返回NA以外的值。(NA将被视为0(。如果要返回这些行的NA,请将all更改为any

library(tidyverse)
ID <- c("A","B","C","D","E","F")
Q1 <- c(0,1,7,9,NA,3) 
Q2 <- c(0,3,2,2,NA,3) 
Q3 <- c(0,0,7,9,NA,3) 
dta <- data.frame(ID,Q1,Q2,Q3) 
dta %>%
pivot_longer(-ID) %>%
group_by(ID) %>%
mutate(ProxySum = ifelse(all(is.na(value)), NA, sum(value[which(value<7)]))) %>%
pivot_wider()
#> # A tibble: 6 × 5
#> # Groups:   ID [6]
#>   ID    ProxySum    Q1    Q2    Q3
#>   <chr>    <dbl> <dbl> <dbl> <dbl>
#> 1 A            0     0     0     0
#> 2 B            4     1     3     0
#> 3 C            2     7     2     7
#> 4 D            2     9     2     9
#> 5 E           NA    NA    NA    NA
#> 6 F            9     3     3     3

创建于2021-12-14由reprex包(v2.0.1(

更新:请参阅与stefan:相同的解决方案的@tjebo注释

这里有一个不完全相同的解决方案:使用hablar:

library(dplyr)
library(hablar)
dta %>% 
rowwise() %>% 
mutate(sum = sum_(across(Q1:Q3, ~case_when(.<7 ~sum_(.)))))

第一个答案:可能与stefan的答案相同:

这里是另一个dplyr解决方案:

library(dplyr)
dta %>% 
mutate(across(where(is.numeric), ~ifelse(.>=7,0,.)),
sum = rowSums(across(where(is.numeric))))
ID Q1 Q2 Q3 sum
1  A  0  0  0   0
2  B  1  3  0   4
3  C  0  2  0   2
4  D  0  2  0   2
5  E NA NA NA  NA
6  F  3  3  3   9

最新更新