规范化多个变量以分离控制值

问题描述 投票:1回答:3

我感兴趣的是将多个变量归一化到控制子组的相应平均值。

假设我有一个数据框,我从3个不同的条件(对照,药物1,药物2)测量两个变量(分数1和分数2)。

df <- data.frame(Treatment=rep(c( "Control", "Drug 1",
    "Drug 2"), each=6 ),
    Score1=c(4,5,4,5,5,6,8,9,10,8,9,9,14,15,13,15,14,15), 
    Score2=c(1,2,1,2,3,3,8,8,9,9,8,8,14,14,15,12,14,15)) 
df

   Treatment Score1 Score2
1    Control      4      1
2    Control      5      2
3    Control      4      1
4    Control      5      2
5    Control      5      3
6    Control      6      3
7     Drug 1      8      8
8     Drug 1      9      8
9     Drug 1     10      9
10    Drug 1      8      9
11    Drug 1      9      8
12    Drug 1      9      8
13    Drug 2     14     14
14    Drug 2     15     14
15    Drug 2     13     15
16    Drug 2     15     12
17    Drug 2     14     14
18    Drug 2     15     15

我想将每个分数标准化为对照组的平均值(对于该分数)。最终结果是:

df.normal <- df
x <- mean(df$Score1[df$Treatment=="Control"])
y <- mean(df$Score2[df$Treatment=="Control"])
df.normal$Score1_normalised <- df$Score1 / x
df.normal$Score2_normalised <- df$Score2 / y
df.normal

Treatment Score1 Score2 Score1_normalised Score2_normalised
1    Control      4      1         0.8275862               0.5
2    Control      5      2         1.0344828               1.0
3    Control      4      1         0.8275862               0.5
4    Control      5      2         1.0344828               1.0
5    Control      5      3         1.0344828               1.5
6    Control      6      3         1.2413793               1.5
7     Drug 1      8      8         1.6551724               4.0
8     Drug 1      9      8         1.8620690               4.0
9     Drug 1     10      9         2.0689655               4.5
10    Drug 1      8      9         1.6551724               4.5
11    Drug 1      9      8         1.8620690               4.0
12    Drug 1      9      8         1.8620690               4.0
13    Drug 2     14     14         2.8965517               7.0
14    Drug 2     15     14         3.1034483               7.0
15    Drug 2     13     15         2.6896552               7.5
16    Drug 2     15     12         3.1034483               6.0
17    Drug 2     14     14         2.8965517               7.0
18    Drug 2     15     15         3.1034483               7.5

我认为这对dplyr是可能的,但我一直在努力开始,因为我有大约20个变量,我希望有一个捷径,而不是长途跋涉。

任何帮助将不胜感激!

r dplyr
3个回答
0
投票

这是使用aggregate()和mapply():

> Medias <- aggregate(df[c("Score1", "Score2")], list(df$Treatment), mean)
> Medias
  Group.1    Score1    Score2
1 Control  4.833333  2.000000
2  Drug 1  8.833333  8.333333
3  Drug 2 14.333333 14.000000
> 
> mapply( function(x, y) {x / y}, x = df[c("Score1", "Score2")], y = Medias[Medias$Group.1 == "Control" , c("Score1", "Score2")])
         Score1 Score2
 [1,] 0.8275862    0.5
 [2,] 1.0344828    1.0
 [3,] 0.8275862    0.5
 [4,] 1.0344828    1.0
 [5,] 1.0344828    1.5
 [6,] 1.2413793    1.5
 [7,] 1.6551724    4.0
 [8,] 1.8620690    4.0
 [9,] 2.0689655    4.5
[10,] 1.6551724    4.5
[11,] 1.8620690    4.0
[12,] 1.8620690    4.0
[13,] 2.8965517    7.0
[14,] 3.1034483    7.0
[15,] 2.6896552    7.5
[16,] 3.1034483    6.0
[17,] 2.8965517    7.0
[18,] 3.1034483    7.5
> 

希望能帮助到你。


0
投票

这是一个dplyr + tidyr工作流程。它很好地扩展,但不幸的是,当你需要进行一些重塑时,它会变得有点复杂。

使用一些基本的dplyr动词,您可以获得控制值并计算以"Score"开头的任何列的均值。由于该数据框只有一行,因此您可以在规范化df时轻松使用这些平均分数。

library(dplyr)

control_means <- df %>%
  filter(Treatment == "Control") %>%
  summarise_at(vars(starts_with("Score")), mean)

df %>%
  mutate(Score1_norm = Score1 / control_means$Score1,
         Score2_norm = Score2 / control_means$Score2) %>%
  head()
#>   Treatment Score1 Score2 Score1_norm Score2_norm
#> 1   Control      4      1   0.8275862         0.5
#> 2   Control      5      2   1.0344828         1.0
#> 3   Control      4      1   0.8275862         0.5
#> 4   Control      5      2   1.0344828         1.0
#> 5   Control      5      3   1.0344828         1.5
#> 6   Control      6      3   1.2413793         1.5

但是,对于更多得分列重复此操作将很快变旧。通常你可以使用mutate_at减少重复,但我认为这不会很有效,因为你每次都会引入一个不同的control_means列。

相反,你可以将手段和数据重新塑造成长形状,然后按分组(不知道你还称之为别的东西)加入得分1,得分2等。

control_means_long <- control_means %>%
  gather(key = group, value = mean_score)

control_means_long
#>    group mean_score
#> 1 Score1   4.833333
#> 2 Score2   2.000000

df %>%
  gather(key = group, value = score, starts_with("Score")) %>%
  left_join(control_means_long, by = "group") %>%
  mutate(score_norm = score / mean_score) %>%
  head()
#>   Treatment  group score mean_score score_norm
#> 1   Control Score1     4   4.833333  0.8275862
#> 2   Control Score1     5   4.833333  1.0344828
#> 3   Control Score1     4   4.833333  0.8275862
#> 4   Control Score1     5   4.833333  1.0344828
#> 5   Control Score1     5   4.833333  1.0344828
#> 6   Control Score1     6   4.833333  1.2413793

您可能希望在此之后删除均值列。如果把它保留在那种格式中就可以了,那么你就完成了。但是如果你需要重新开始像你开始那样的广泛形状,你必须进行几轮重塑。

在计算之后,我正在创建一个score_type列,以显示值是gather的测量值或标准值。然后将该文本与该组一起制作一列Score1_measuredScore1_normed等。添加临时行号以使spread正确匹配这些分数,然后将其放回大范围内。

df %>%
  gather(key = group, value = measured, starts_with("Score")) %>%
  left_join(control_means_long, by = "group") %>%
  mutate(normed = measured / mean_score) %>%
  select(-mean_score) %>%
  gather(key = score_type, value = value, measured, normed) %>%
  unite(group_and_type, group, score_type) %>%
  group_by(group_and_type) %>%
  mutate(row = row_number()) %>%
  spread(key = group_and_type, value = value) %>%
  select(-row) %>%
  head()
#> # A tibble: 6 x 5
#>   Treatment Score1_measured Score1_normed Score2_measured Score2_normed
#>   <fct>               <dbl>         <dbl>           <dbl>         <dbl>
#> 1 Control                 4         0.828               1           0.5
#> 2 Control                 5         1.03                2           1  
#> 3 Control                 4         0.828               1           0.5
#> 4 Control                 5         1.03                2           1  
#> 5 Control                 5         1.03                3           1.5
#> 6 Control                 6         1.24                3           1.5

reprex package创建于2019-02-19(v0.2.1)


0
投票

非常感谢你的建议!我应该在我的问题中更清楚地知道我在这里命名为“得分1和得分2”的变量实际上在我的数据集中被命名为一堆不同的东西,例如面积,数量,长度等。

最终为我工作的是dplyr和mapply的组合。虽然我很欣赏有用的dplyr技巧Camille!

我获得了所有变量的平均值(按处理分组),如下所示:

Means<- df %>% group_by(Treatment) %>%          
    summarise_each(funs(mean(., na.rm = TRUE)))

然后使用mapply通过其控制处理方法对每个变量进行归一化:

normalised.df <-mapply( function(x,y) {x / y},
                             x = df[c("area", "number", "length")],
                             y = Means[Means$Treatment == "Control", c("area", "number", "length")])

非常感谢!

© www.soinside.com 2019 - 2024. All rights reserved.