首页 > 解决方案 > 通过控制组为几个子组中的每一个划分整个数据帧

问题描述

起始数据

我在 R 工作,我有一组数据来自用不同剂量的不同药物治疗的动物组(队列)。我的数据集的简化可重现示例如下:

# set starting values for simulation of animal cohorts across doses of various drugs with a few numeric endpoints
cohort_size <- 3
animals <- letters[1:cohort_size]
drugs <- factor(c("A", "B", "C"))
doses <- factor(c(0, 10, 100))
total_size <- cohort_size * length(drugs) * length(doses)

# simulate data based on above parameters
df <- cbind(expand.grid(drug = drugs, dose = doses, animal = animals),
            data.frame(
              other_metadata = sample(LETTERS[24:26], size = total_size, replace = TRUE),
              num1 = rnorm(total_size, mean = 10, sd = 3), 
              num2 = rnorm(total_size, mean = 60, sd = 9),
              num3 = runif(total_size, min = 1, max = 5)))

这会产生类似的东西:

##   drug dose animal other_metadata      num1     num2     num3
## 1    A    0      a              X  6.448411 54.49473 4.111368
## 2    B    0      a              Y  9.439396 67.39118 4.917354
## 3    C    0      a              Y  8.519773 67.11086 3.969524
## 4    A   10      a              Z  6.286326 69.25982 2.194252
## 5    B   10      a              Y 12.428265 70.32093 1.679301
## 6    C   10      a              X 13.278707 68.37053 1.746217

我的目标

对于每种药物治疗,我将dose == 0动物视为该药物的对照组(假设每个动物在不同的时间运行并且有自己的对照组)。我希望计算对照组的每个数字端点(本例中为 5:7 列)的平均值。接下来,我想通过其各自对照组的平均值对每只动物的每个数字端点(列 5:7)进行归一化(除)。

换句话说num1,对于所有动物,drug == "A"应该除以num1所有动物的平均值,对于每个端点drug == "A"dose == 0以此类推。

最终输出的大小应与原始输出相同data.frame,左侧的所有非数字元数据列保持不变,所有数字数据列现在都具有标准化值。

自然,我想找到最简单的解决方案 - 尽量减少新变量的创建,如果可能的话,最好在单个 dplyr 管道中。

到目前为止我尝试过的

我应该说我已经在技术上解决了这个问题,但是这个解决方案非常难看,有很多步骤,所以我希望能得到帮助以找到一个更优雅的解决方案。

我知道我可以很容易地将对照组的平均值转换为新的data.frame使用:

df %>% 
  filter(dose == 0) %>%
  group_by(drug, dose) %>%
  summarise_all(mean) 

我已经研究了几件事,但无法弄清楚如何实现它们。按照对我来说最有希望的顺序:

  1. dplyr::group_modify()
  2. dplyr::rowwise()
  3. sweep()在某种类型的循环中

提前感谢您提供的任何帮助!

标签: rdplyr

解决方案


如果打算将数字列除以mean对照组的值,按“药物”分组,在按“药物”分组后,使用mutatewith across(from dplyr 1.0.0),除以列值 ( .with meanof the values where the 'dose'是 0

library(dplyr) # 1.0.0
df %>% 
   group_by(drug) %>% 
   mutate(across(where(is.numeric), ~ ./mean(.[dose == 0])))

如果我们的 dplyr 版本是<1.0.0,请使用mutate_if

df %>%
    group_by(drug) %>%
    mutate_if(is.numeric, ~ ./mean(.[dose == 0]))

推荐阅读