我有一个包含列group_ID
和class
的数据框,以及多个数字要素和一些字符元数据,即:
group_ID class var1 var2 var3 metadata
a foo 1 324 3 cat
a bar 1.3 34 53 dog
a baz 31 34 5 elephant
b foo 34 34 943 dolphin
b bar 94 51 23 chipmunk
b baz 985 595 43 badger
c foo 43 93 23 tapir
c bar 43 23 23 monkey
c baz 40 53 512 duck
我想计算每个foo
的课程group_ID
的中位数,然后将每行除以与group_ID
匹配的中位数。
在此示例中,每个foo
只有1行,因此中位数与初始值相同,但实际上每个class
和{{1}都有很多行}。
有一种简单的方法吗?我对far的最佳尝试包括为group_ID
的中值创建一个单独的数据帧,然后通过group_ID进行拆分并在一个可怕的循环中进行扫描,但最终我失去了元数据列。这样做似乎很常见,我确定我错过了什么。
任何帮助都将不胜感激。
答案 0 :(得分:7)
我们可以使用mutate_each
中的dplyr
除以条件。
library(dplyr)
df %>% group_by(group_ID) %>%
mutate_each(funs(./median(.[class == "foo"])), var1:var3)
# Source: local data frame [9 x 6]
# Groups: group_ID
#
# group_ID class var1 var2 var3 metadata
# 1 a foo 1.0000000 1.0000000 1.00000000 cat
# 2 a bar 1.3000000 0.1049383 17.66666667 dog
# 3 a baz 31.0000000 0.1049383 1.66666667 elephant
# 4 b foo 1.0000000 1.0000000 1.00000000 dolphin
# 5 b bar 2.7647059 1.5000000 0.02439024 chipmunk
# 6 b baz 28.9705882 17.5000000 0.04559915 badger
# 7 c foo 1.0000000 1.0000000 1.00000000 tapir
# 8 c bar 1.0000000 0.2473118 1.00000000 monkey
# 9 c baz 0.9302326 0.5698925 22.26086957 duck
如果OP希望将这些列添加为新的/附加列并保持以前的数据不变,您可以将上述方法修改为:
df %>%
group_by(group_ID) %>%
mutate_each(funs(./median(.[class == "foo"])), setNames(var1:var3, paste0("varN", 1:3)))
答案 1 :(得分:5)
这是一个data.table
解决方案。我们转换了' data.frame'到' data.table' (setDT(df)
),按' group_ID'分组,我们循环(使用lapply
)通过以列名称开头的列子集' var' (使用grep
我们进行子集化),将每列与该列的median
子集相对应,该列对应于' foo' ' class'中的价值。这可以作为新列分配(:=
),也可以将其分配回同一列以替换原始列。替换原始列的一个问题是我们应该将原始的class
与替换的列匹配。如果是原来的' var'列为numeric
,然后它将用作median
计算,并将新列转换为numeric
。如果原始列为integer
类,则可能的选项是将类更改为numeric
然后分配。
library(data.table)
setDT(df)[, paste0("varN", 1:3) := lapply(.SD[,
grep("^var", names(.SD)), with=FALSE],
function(x) x/median(x[class=="foo"])), group_ID]
df
# group_ID class var1 var2 var3 metadata varN1 varN2 varN3
#1: a foo 1.0 324 3 cat 1.0000000 1.0000000 1.00000000
#2: a bar 1.3 34 53 dog 1.3000000 0.1049383 17.66666667
#3: a baz 31.0 34 5 elephant 31.0000000 0.1049383 1.66666667
#4: b foo 34.0 34 943 dolphin 1.0000000 1.0000000 1.00000000
#5: b bar 94.0 51 23 chipmunk 2.7647059 1.5000000 0.02439024
#6: b baz 985.0 595 43 badger 28.9705882 17.5000000 0.04559915
#7: c foo 43.0 93 23 tapir 1.0000000 1.0000000 1.00000000
#8: c bar 43.0 23 23 monkey 1.0000000 0.2473118 1.00000000
#9: c baz 40.0 53 512 duck 0.9302326 0.5698925 22.26086957
答案 2 :(得分:3)
1)by 这是基础R解决方案:
do.call("rbind", by(DF, DF$group_ID, function(d)
data.frame(d, sapply(d[3:5], function(x) x / median(x[d$class == "foo"])))
))
,并提供:
group_ID class var1 var2 var3 metadata var1.1 var2.1 var3.1
a.1 a foo 1.0 324 3 cat 1.0000000 1.0000000 1.00000000
a.2 a bar 1.3 34 53 dog 1.3000000 0.1049383 17.66666667
a.3 a baz 31.0 34 5 elephant 31.0000000 0.1049383 1.66666667
b.4 b foo 34.0 34 943 dolphin 1.0000000 1.0000000 1.00000000
b.5 b bar 94.0 51 23 chipmunk 2.7647059 1.5000000 0.02439024
b.6 b baz 985.0 595 43 badger 28.9705882 17.5000000 0.04559915
c.7 c foo 43.0 93 23 tapir 1.0000000 1.0000000 1.00000000
c.8 c bar 43.0 23 23 monkey 1.0000000 0.2473118 1.00000000
c.9 c baz 40.0 53 512 duck 0.9302326 0.5698925 22.26086957
2)by / sweep 使用sweep
的替代方案,而且只有基本函数是:
do.call("rbind", by(DF, DF$group_ID, function(d) {
med <- apply(subset(d, class == "foo")[3:5], 2, median)
data.frame(d, sweep(as.matrix(d[3:5]), 2, med, "/"))
}))
3)sapply / ave 另一个基本解决方案是将ave
应用于每个var
列:
data.frame(DF, sapply(names(DF[3:5]), function(j)
ave(1:nrow(DF), DF$group_ID, FUN = function(i)
DF[i, j] / median(subset(DF[i, ], class == "foo")[[j]]))
))
注意:可重复形式的输入DF
为:
DF <- structure(list(group_ID = structure(c(1L, 1L, 1L, 2L, 2L, 2L,
3L, 3L, 3L), .Label = c("a", "b", "c"), class = "factor"), class = structure(c(3L,
1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L), .Label = c("bar", "baz", "foo"
), class = "factor"), var1 = c(1, 1.3, 31, 34, 94, 985, 43, 43,
40), var2 = c(324L, 34L, 34L, 34L, 51L, 595L, 93L, 23L, 53L),
var3 = c(3L, 53L, 5L, 943L, 23L, 43L, 23L, 23L, 512L), metadata = structure(c(2L,
4L, 7L, 5L, 3L, 1L, 9L, 8L, 6L), .Label = c("badger", "cat",
"chipmunk", "dog", "dolphin", "duck", "elephant", "monkey",
"tapir"), class = "factor")), .Names = c("group_ID", "class",
"var1", "var2", "var3", "metadata"), class = "data.frame", row.names = c(NA,
-9L))