2016-03-01 28 views
2

我具有包含列group_IDclass,以及多个数字特征的数据帧,而一些字符的元数据,即:由单独的组中位数除以数据帧组

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行,因此中位数将与初始值相同,但实际上我对于每个classgroup_ID有许多行。


有没有简单的方法来做到这一点?我的最佳尝试包括为foo的中间值创建一个单独的数据框,然后按group_ID分割并扫描一个可怕的循环,但最终丢失了元数据列。这似乎是一件很常见的事情,我确信我错过了一些东西。

任何帮助,将不胜感激。

+0

这适用于我,但您应该添加此示例的预期结果,以确保'df%>%group_by(group_ID)%>% mutate_每个(funs(./中位数(。[class ==“bar”])),var1:var3)' –

回答

7

dplyr可以使用mutate_each除以条件。

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))) 
+0

谢谢@docendodiscimus –

+0

谢谢,看起来应该这样做。毫不奇怪有一个dplyr解决方案。 –

5

这里是一个data.table解决方案。我们将'data.frame'转换为'data.table'(setDT(df)),按'group_ID'分组,我们循环(使用lapply)通过以列名“var”开头的列子集(使用grep我们是子集),将每列除以该列的子集的median,该列对应'class'中的'foo'值。这可以指定为(:=)作为新列,或者我们可以将其分配回同一列以替换原始列。更换原始色谱柱的一个问题是,我们应该将原件的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 
+0

@PierreLafortune我之前忘记在'grep'中使用'.SD',并且有点忙于开会。 – akrun

+2

统计学考虑它。对于你收到的几百个upvotes,你会得到一个downvote。统计上不重要。 :) –

+0

谢谢你们的评论。 – akrun

3

1)由这里是一个基础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)/扫使用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))