r - 使用 dplyr 和 tidyr 逐行划分行
问题描述
我正在尝试使用 dplyr 处理(相当大的)数据集,我相信我的问题源于对“summarise_if”函数的使用不当。这是一些生成看起来像我的虚拟数据的代码:
df <- data.frame(Block = c(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4),
Treatment = c(rep("Control", 4), rep("CF", 4), rep("LR", 4)),
var1 = c(9, 12, 15, 16, 11, 9, 13, 11, 5, 11, 5, 11),
var2 = c(0, 4, 9, 3, 6, 0, 0, 10, 15, 25, 0, 0))
我想按块和处理对数据进行分组,然后,对于每个变量(var1、var2、...),我想将“处理”值除以每个块的“控制”值。生成的数据框看起来像这样(我还没有为我的虚拟数据完成所有数学运算,所以我只是将示例公式放在每个单元格中应该计算的内容):
Treatment Block var1 var2
CF 1 CF/control CF/control
CF 2 CF/control CF/control
CF 3 CF/control CF/control
CF 4 CF/control CF/control
LR 1 LR/control LR/control
LR 2 LR/control LR/control
LR 3 LR/control LR/control
LR 4 LR/control LR/control
一些值将是 NaN 或无穷大,因为我在某些处理中除以零,但这没关系。
我可以使用以下代码一次为单个变量和处理生成我想要的内容:
df %>%
dplyr::group_by(Block) %>%
dplyr::summarise(value = var1[Treatment=="CF"] / var1[Treatment=="Control"])
但这在许多变量和治疗中变得乏味。但是,当我尝试对整个数据框执行此操作时,我会遇到各种错误。我最好的猜测是这样的:
df %>%
dplyr::group_by(Block, Treatment) %>%
dplyr::summarise_if(is.numeric, value = .[Treatment=="CF"] / .[Treatment=="Control"])
这给了我错误“未找到对象'治疗'”,并且仍然迫使我逐个治疗。
任何帮助表示赞赏!
解决方案
您可以使用以下内容:
df %>%
dplyr::group_by(Block) %>%
dplyr::summarise(across(where(is.numeric),
list(CF = ~.[Treatment=="CF"] / .[Treatment=="Control"],
LR = ~.[Treatment=="LR"] / .[Treatment=="Control"])))
# Block var1_CF var1_LR var2_CF var2_LR
# <dbl> <dbl> <dbl> <dbl> <dbl>
#1 1 1.22 0.556 Inf Inf
#2 2 0.75 0.917 0 6.25
#3 3 0.867 0.333 0 0
#4 4 0.688 0.688 3.33 0
如果您希望输出遵循与预期输出中所示相同的格式,您可以使用pivot_longer
.
df %>%
dplyr::group_by(Block) %>%
dplyr::summarise(across(where(is.numeric),
list(CF = ~.[Treatment=="CF"] / .[Treatment=="Control"],
LR = ~.[Treatment=="LR"] / .[Treatment=="Control"]))) %>%
tidyr::pivot_longer(cols = -Block,
names_to = c('.value', 'Treatment'),
names_sep = '_')
# Block Treatment var1 var2
# <dbl> <chr> <dbl> <dbl>
#1 1 CF 1.22 Inf
#2 1 LR 0.556 Inf
#3 2 CF 0.75 0
#4 2 LR 0.917 6.25
#5 3 CF 0.867 0
#6 3 LR 0.333 0
#7 4 CF 0.688 3.33
#8 4 LR 0.688 0