【问题标题】:R- Subtracting the mean of a group from each element of that group in a dataframeR-从数据框中该组的每个元素中减去该组的平均值
【发布时间】:2018-06-28 00:09:11
【问题描述】:

我正在尝试将向量“意味着”合并到数据框。 我的数据框看起来像这样Data = growth

我首先使用以下命令计算了不同组的所有平均值(1 组 = 人口 + 温度 + 大小 + 复制):

means<-aggregate(TL ~ Population + Temperature + Replicat + Size + Measurement, data=growth, list=growth$Name, mean)        

然后,我选择测量 1 的方法如下,因为我只对这些方法感兴趣。

meansT0<-means[which(means$Measurement=="1"),]    

现在,我想将此均值向量合并到我的数据框 (=growth) 中,以便每个组的正确均值对应于数据框的右侧部分。

然后,目标是根据其所属组(以及除测量 1 之外的所有其他测量)将每个组(在测量 1 处)的平均值减去数据帧的每个元素。也许不需要将手段列添加到数据框中?你知道有什么命令可以做到这一点吗?

[27.06.18] 我制作了这个简化的数据框,希望这有助于理解。 所以,我想要的是,对于数据框中的每个个体和每个测量值(这里只有测量值 1 和测量值 2,通常我有更多),其在 MEASUREMENT 1 处所属组的平均值。

所以,如果我按组(1 组= 人口 + 温度 + 测量值)获得平均值:

means<-aggregate(TL ~ Population + Temperature + Measurement, data=growth, list=growth$Name, mean)
means               

我得到了这些平均值(在这个例子中):

Population Temperature Measurement       TL
JUB          15           **1**           **12.00000**
JUB          20           **1**           **15.66667**
JUB          15           2           17.66667
JUB          20           2           18.66667
JUB          15           3           23.66667
JUB          20           3           24.33333

我们只对 MEASUREMENT 1 的方法感兴趣。对于数据帧中的每个人,我想在 Measurement 1 处减去其所属组的平均值:在此示例中(请参阅带有 R 命令的数据帧): -对于 JUB+15+Measurement 1 组,平均值 = 12 -对于 JUB+20+Measurement 1 组,平均值 = 15.66

growth<-data.frame(Population=c("JUB", "JUB", "JUB","JUB", "JUB", "JUB","JUB", "JUB", "JUB","JUB", "JUB", "JUB","JUB", "JUB", "JUB","JUB", "JUB", "JUB"), Measurement=c("1","1","1","1","1","1","2","2","2","2","2","2", "3", "3", "3", "3", "3", "3"),Temperature=c("15","15","15","20", "20", "20","15","15","15","20", "20", "20","15","15","15","20", "20", "20"),TL=c(11,12,13,15,18,14, 16,17,20,21,19,16, 25,22,24,26,24,23), New_TL=c("11-12", "12-12", "13-12", "15-15.66", "18-15.66", "14-15.66", "16-12", "17-12", "20-12", "21-15.66", "19-15.66", "16-15.66", "25-12", "22-12", "24-12", "26-15.66", "24-15.66", "23-15.66"))    
print(growth)

我希望通过这个,你可以更好地理解我想要做什么。我有很多数据,如果我必须手动执行此操作,这将花费我很多时间并增加我犯错的风险。

【问题讨论】:

  • 请设置一个可重现的示例(无屏幕截图),该示例也显示所需的结果。

标签: r


【解决方案1】:

这是tidyverse 的选项。按组列分组后,使用mutate_at指定感兴趣的列,并获取该列(.)与它的mean的差异。

library(tidyverse)
growth %>% 
       group_by(Population, Temperature, Replicat, Size, Measurement) %>% 
       mutate_at(vars(HL, TL), funs(MeanGroupDiff = . 
                  - mean(.[Measurement == 1])))

使用mtcars 数据集的可重现示例

data(mtcars)
mtcars %>%
   group_by(cyl, vs) %>% 
   mutate_at(vars(mpg, disp), funs(MeanGroupDiff = .- mean(.[am==1])))

【讨论】:

  • 感谢您的回复。我意识到我的帖子不够清楚,并澄清了我上面的描述。对于用于在数据框中计算均值(人口 + 温度 + 大小 + 复制 + 测量)的每组的每个人,我想将每组的每个人(人口 + 温度 + 大小 + 复制 + 测量)的平均值作为测量 1 组(种群 + 温度 + 大小 + 重复,测量 1)。
  • 所以实际上,我要减去的并不是其所属组的平均值,而是在测量 1 处为组计算的平均值。这是为了在实验开始时控制大小.希望我的解释更清楚。我在上面设置了一个示例,显示了我要解释的内容。也许这会更容易理解。
  • @Marine 不确定我是否清楚。你能检查更新的解决方案吗
  • funs 从 dplyr 0.8 开始被软性弃用。替换类似于mutate_at(vars(mpg, disp), .funs = list(MeanGroupDiff = .- mean(.[am==1]))),但这样做时我得到Error in check_names_df(i, x): object 'am' not found
  • @MaxGhenis 可能是list(MeanGroupDiff = ~ . - mean(.[am == 1]))
【解决方案2】:

您是否考虑过使用data.table 包?它非常适合执行您描述的这类分组、过滤、连接和聚合操作,从长远来看可能会为您节省大量时间。

下面的代码显示了与您描述的工作流类似但基于内置mtcars 数据集的工作流在使用data.table 时的外观。

需要明确的是,还有一些方法可以使用 base R 以及其他包(如 dplyr)来执行您所描述的操作,只是根据我发现对我最有用的内容提出建议个人作品。

library(data.table)

## Convert mtcars to a data.table
## only include columns `mpg`, `cyl`, `am` and `gear` for brevity
DT <- as.data.table(mtcars)[, .(mpg, cyl,am, gear)]

## Take a subset where `cyl` is equal to 6
DT <- DT[cyl == 6]

## Calculate grouped mean based on `gear` and `am` as grouping variables
DT[,group_mpg_avg := mean(mpg), keyby = .(gear, am)]

## Calculate each row's difference from the group mean
DT[,mpg_diff_from_group := mpg - group_mpg_avg]

print(DT)

#     mpg cyl am gear group_mpg_avg mpg_diff_from_group
# 1: 21.4   6  0    3         19.75                1.65
# 2: 18.1   6  0    3         19.75               -1.65
# 3: 19.2   6  0    4         18.50                0.70
# 4: 17.8   6  0    4         18.50               -0.70
# 5: 21.0   6  1    4         21.00                0.00
# 6: 21.0   6  1    4         21.00                0.00
# 7: 19.7   6  1    5         19.70                0.00

【讨论】:

  • 感谢您的回复。我意识到我的帖子不够清楚,并澄清了我上面的描述。对于数据框中的每个人,我想减去在 MEASUREMENT 1 计算的所属组的平均值。我在上面设置了一个示例。我尝试了您提供的代码来添加均值列,但它对我不起作用。我收到此错误消息:[.data.table(growth2, , :=(means_groups, mean("TL")), keyby = .("Population", : The items in the 'by' or 'keyby' list是长度 (1,1,1,1,1)。每个长度必须与 x 中的行或 i (3365) 返回的行数相同。
【解决方案3】:

考虑 by 按因子对您的数据框进行子集化(但省略 Measurement 以便比较第 1 组和所有其他组)。然后,对所需列运行ifelse 条件逻辑计算。由于by会返回一个数据框列表,所以在外面绑定do.call()

df_list <- by(growth, growth[,c("Population", "Temperature")], function(sub) {
  # TL CORRECTION      
  sub$Correct_TL <- ifelse(sub$Measurement != 1, 
                           sub$TL - mean(subset(sub, Measurement == 1)$TL),
                           sub$TL)
  # ADD OTHER CORRECTIONS

  return(sub)  
})

final_df <- do.call(rbind, df_list)

输出 (使用发布的数据)

final_df

#    Population Measurement Temperature TL   New_TL Correct_TL
# 1         JUB           1          15 11    11-12 11.0000000
# 2         JUB           1          15 12    12-12 12.0000000
# 3         JUB           1          15 13    13-12 13.0000000
# 7         JUB           2          15 16    16-12  4.0000000
# 8         JUB           2          15 17    17-12  5.0000000
# 9         JUB           2          15 20    20-12  8.0000000
# 13        JUB           3          15 25    25-12 13.0000000
# 14        JUB           3          15 22    22-12 10.0000000
# 15        JUB           3          15 24    24-12 12.0000000
# 4         JUB           1          20 15 15-15.66 15.0000000
# 5         JUB           1          20 18 18-15.66 18.0000000
# 6         JUB           1          20 14 14-15.66 14.0000000
# 10        JUB           2          20 21 21-15.66  5.3333333
# 11        JUB           2          20 19 19-15.66  3.3333333
# 12        JUB           2          20 16 16-15.66  0.3333333
# 16        JUB           3          20 26 26-15.66 10.3333333
# 17        JUB           3          20 24 24-15.66  8.3333333
# 18        JUB           3          20 23 23-15.66  7.3333333

【讨论】:

  • 感谢您的回复。该命令有效。但是,通过这样做,我得到一个新列,它是数据框的每个元素与其组的平均值之间的差异(在本例中为人口 + 温度 + 复制 + 大小 + 测量)。我需要的是在测量 1(当我第一次测量个人时)将每个组的平均值减去数据帧的每个元素,仍然基于他们的所属组,但是对于测量 2、3 和 4。实际上,这个是在实验开始时对 TL(总长度)进行“更正”。
  • 我几乎知道这并不完全是您所需要的,因此我在您的帖子下方发表了评论。请展示而不是仅仅用实际的当前数据和期望的结果来讲述。请参阅:How to make a great R reproducible example?
  • 我试图建立一个例子。我在描述中添加了它,解释和代码。我希望你能帮助我解决这个问题。
  • 非常感谢!这工作得很好。我可以为整张桌子做这件事。碰巧,你知道如何做同样的事情但有一些价值观吗?事实上,从另一个表中,我需要根据每个人的人口对每个人减去 3 个不同的值(对于 3 个不同的人口)。例如,对于来自人口 JUB 的个人,我需要减去该人口的某个值,即 12;对于来自人口 ZHA 的个人,我需要将每个人减去 15;对于来自 SEB 人口的个人,我需要将 14 减去每个人。
  • 听起来不错。乐意效劳!请注意 StackOverflow 的说法 thanks!
猜你喜欢
  • 1970-01-01
  • 2019-03-05
  • 1970-01-01
  • 2016-05-12
  • 2020-05-22
  • 2014-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多