2016-03-01 62 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))