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