我有一个R格式的数据框,格式如下:
@@NESTLEVEL
等有5种不同的处理方法,3个样本和10个时间点。大约还有50列各种测量值,名称不相关-我在这里只显示第一个,M1。
对于这50个测量值中的每个测量值,我想从所有后续时间点中减去它们在零时间处保持的值。例如,M1随后将如下所示:
Treatment Sample Time_point M1
A 1 0 0.12
A 2 0 0.45
A 3 0 0.35
A 1 1 0.76
A 2 1 0.45
A 3 1 0.41
A 1 2 0.94
A 2 2 0.55
A 3 2 0.44
我不知道该怎么做。我首先提取时间点零值,然后重复序列,然后减去它们。但是,我只能使它一次只能处理一列,这有点令人费解。我想知道是否有一种方法可以在管道中使用group_by和mutate来更改每列的值,但是找不到一种方法来指定需要减去的值。
答案 0 :(得分:3)
d$M1 - ave(d$M1, d$Sample, d$Treatment, FUN = function(x) x[1])
#[1] 0.00 0.00 0.00 0.64 0.00 0.06 0.82 0.10 0.09
对于不止一列,请尝试
nm = c("M1") #Add column names here
sapply(nm, function(s){
d[[s]] - ave(d[[s]], d$Sample, d$Treatment, FUN = function(x) x[1])
})
# M1
# [1,] 0.00
# [2,] 0.00
# [3,] 0.00
# [4,] 0.64
# [5,] 0.00
# [6,] 0.06
# [7,] 0.82
# [8,] 0.10
# [9,] 0.09
等效的tidyverse
将是
d %>% group_by(Sample, Treatment) %>% mutate_at(nm, function(x) x - x[1])
答案 1 :(得分:2)
使用dplyr
,您可以尝试:
df %>%
group_by_at(1:2) %>%
mutate(M1 = M1 - first(M1))
Treatment Sample Time_point M1
<chr> <int> <int> <dbl>
1 A 1 0 0
2 A 2 0 0
3 A 3 0 0
4 A 1 1 0.64
5 A 2 1 0
6 A 3 1 0.06
7 A 1 2 0.82
8 A 2 2 0.1
9 A 3 2 0.09
或对第4列中的所有列执行此操作:
df %>%
group_by_at(1:2) %>%
mutate_at(4:length(.), ~ . - first(.))
如果您需要先安排数据:
df %>%
arrange_at(1:3) %>%
group_by_at(1:2) %>%
mutate(M1 = M1 - first(M1))
或针对多列:
df %>%
arrange_at(1:3) %>%
group_by_at(1:2) %>%
mutate_at(4:length(.), ~ . - first(.))
答案 2 :(得分:1)
您可以与时间为0的数据子集联接,并使用data.table的更新联接功能。请注意,这将更新原始data.frame,而不是创建新的data.frame。
library(data.table)
setDT(df)
df[df[Time_point == 0], on = .(Treatment, Sample),
M1 := M1 - i.M1]
# Treatment Sample Time_point M1
# 1: A 1 0 0.00
# 2: A 2 0 0.00
# 3: A 3 0 0.00
# 4: A 1 1 0.64
# 5: A 2 1 0.00
# 6: A 3 1 0.06
# 7: A 1 2 0.82
# 8: A 2 2 0.10
# 9: A 3 2 0.09
对于多列:
创建示例数据和列名向量
set.seed(2019)
df[, M2 := sample(nrow(df))]
cols <- grep('^M', names(df), value = T)
减去时间0值
df[df[Time_point == 0], on = .(Treatment, Sample),
(cols) := setDT(mget(cols)) - mget(paste0('i.', cols))][]
# Treatment Sample Time_point M1 M2
# 1: A 1 0 0.00 0
# 2: A 2 0 0.00 0
# 3: A 3 0 0.00 0
# 4: A 1 1 0.64 -3
# 5: A 2 1 0.00 -5
# 6: A 3 1 0.06 2
# 7: A 1 2 0.82 2
# 8: A 2 2 0.10 2
# 9: A 3 2 0.09 -1
答案 3 :(得分:1)
尽管IceCreamToucan的回答很好,但我发现它有点复杂。使用data.table
的方式类似于dplyr
:
library(data.table)
setDT(df)
df[,M1 := M1 - M1[0], by = .(Treatment, Sample)]
对于多列:
cols <- grep('^M', names(df), value = T)
df[,c(cols) := lapply(.SD,function(x){x- x[1]}),.SDcols = cols]