2012-05-19 11 views
15

applyまたは関連する関数を使用して、非常に大きなデータフレーム内の各列対の行平均の結果を含む新しいデータフレームを作成するにはどうすればよいですか?列グループに機能を適用する

私は、多くのサンプルでn個の複製測定値を出力する装置を持っています。各測定値はベクトルです(すべての測定値は同じ長さベクトルです)。私は各サンプルのすべての反復測定値の平均(および他の統計値)を計算したいと思います。つまり、連続した列をグループ化して行ごとに計算する必要があります。

単純な例として、2つのサンプルに対して3回の反復測定を行うと、2つの列(サンプルあたり1つ)を持つデータフレームで終わることがあります。dat$adat$bdat$cであり、dat$d,dat$eおよびdat$fの各行の平均である1つです。

ここで私は私がこれをやったが、明らかに私の非常に大きなデータフレームのためには良いではありません。この

  X1   X2 
1 -0.28358147 -0.40067128 
2 0.50608365 1.27513471 
3 -0.07950691 -0.22562957 
4 -0.52542633 0.41103139 
5 0.37758930 -0.46093340 
6 -0.11784382 0.60514586 
7 0.10811540 0.64293184 
8 0.94388455 0.31948189 
9 0.95197629 -0.10668118 
10 -0.32325169 -0.35891702 
11 0.07836345 1.28189698 
12 1.56269017 0.44897971 
13 0.23533617 -0.04165384 
14 -1.11251880 -0.39810121 
15 0.73109533 0.11872758 
16 -0.54599850 1.13332286 

のようなものの後だいくつかの例のデータ

dat <- data.frame(a = rnorm(16), b = rnorm(16), c = rnorm(16), d = rnorm(16), e = rnorm(16), f = rnorm(16)) 

      a   b   c   d   e   f 
1 -0.9089594 -0.8144765 0.872691548 0.4051094 -0.09705234 -1.5100709 
2 0.7993102 0.3243804 0.394560355 0.6646588 0.91033497 2.2504104 
3 0.2963102 -0.2911078 -0.243723116 1.0661698 -0.89747522 -0.8455833 
4 -0.4311512 -0.5997466 -0.545381175 0.3495578 0.38359390 0.4999425 
5 -0.4955802 1.8949285 -0.266580411 1.2773987 -0.79373386 -1.8664651 
6 1.0957793 -0.3326867 -1.116623982 -0.8584253 0.83704172 1.8368212 
7 -0.2529444 0.5792413 -0.001950741 0.2661068 1.17515099 0.4875377 
8 1.2560402 0.1354533 1.440160168 -2.1295397 2.05025701 1.0377283 
9 0.8123061 0.4453768 1.598246016 0.7146553 -1.09476532 0.0600665 
10 0.1084029 -0.4934862 -0.584671816 -0.8096653 1.54466019 -1.8117459 
11 -0.8152812 0.9494620 0.100909570 1.5944528 1.56724269 0.6839954 
12 0.3130357 2.6245864 1.750448404 -0.7494403 1.06055267 1.0358267 
13 1.1976817 -1.2110708 0.719397607 -0.2690107 0.83364274 -0.6895936 
14 -2.1860098 -0.8488031 -0.302743475 -0.7348443 0.34302096 -0.8024803 
15 0.2361756 0.6773727 1.279737692 0.8742478 -0.03064782 -0.4874172 
16 -1.5634527 -0.8276335 0.753090683 2.0394865 0.79006103 0.5704210 

...

です
data.frame(cbind(
apply(cbind(dat$a, dat$b, dat$c), 1, mean), 
apply(cbind(dat$d, dat$e, dat$f), 1, mean) 
)) 

私はapplyとループを試しましたが、それを一緒に得ることはできません。私の実際のデータには数百の列があります。

+0

常に3列ごとですか?あなたはベクトルの名前のベクトルまたはインデックスのベクトルのベクトルを供給していますか?ユーザーuser1317221_Gの回答があなたの後のものではない場合は、おそらくあなたはもっと情報を与える必要があります。 –

+1

後継の場合、上記の質問は、行のグループに関数を適用する(そして、いくつかの異なるアプローチがあります)、このより最近の質問の転置と思われます:http://stackoverflow.com/q/10837258/1036500 – Ben

答えて

14

あなたはインデックスのリストを渡すことでこれはあなたの状況により一般化することがあります。

x <- list(c('a','b','c'), c('d', 'e', 'f')) 
do.call(cbind, lapply(x, function(i) rowMeans(dat[, i]))) 

EDIT

:あなたはあまりにもCOL名前を持っている場合

x <- list(1:3, 4:6) 
do.call(cbind, lapply(x, function(i) rowMeans(dat[, i]))) 

作品:速度が問題(大規模データ・フレーム)であれば、私はdo.callむしろsapply以上でlapplyを選ぶだろう

ちょうど3列ごとにこれを自動化したいと思うかもしれません。私はより良い方法があります知っているが、ここでは、100列のデータセットにある:

dat <- data.frame(matrix(rnorm(16*100), ncol=100)) 

n <- 1:ncol(dat) 
ind <- matrix(c(n, rep(NA, 3 - ncol(dat)%%3)), byrow=TRUE, ncol=3) 
ind <- data.frame(t(na.omit(ind))) 
do.call(cbind, lapply(ind, function(i) rowMeans(dat[, i]))) 

EDITそれでも2 インデックスに満足していません。私はインデックスを渡すためのより良い/より速い方法があると思います。 (移調提案が特に有用であったにもかかわらず、彼が提案したものと、実際には少し異なり、)私はこの思い付い@ joranの提案に触発さ

n <- 1:ncol(dat) 
ind <- data.frame(matrix(c(n, rep(NA, 3 - ncol(dat)%%3)), byrow=F, nrow=3)) 
nonna <- sapply(ind, function(x) all(!is.na(x))) 
ind <- ind[, nonna] 

do.call(cbind, lapply(ind, function(i)rowMeans(dat[, i]))) 
+1

これは、3つの列を結合する必要がないため、最後の列を除外します。 –

+0

はい、あなたの編集はまさに私が探しているものです、ありがとうございます。私の質問がうまく形成されなかったことを申し訳なく思ったのですが、それは無駄な試行の長い時間を費やしていました... – Ben

+1

私はインデックスを作成し、ここにリンクするためのよりよい方法を求めます。 –

7

rowMeans(dat[1:3]) 

C、ベクトル、Bからの行の意味は

rowMeans(dat[4:6]) 

fをすべて1回の呼び出しであなたが

results<-cbind(rowMeans(dat[1:3]),rowMeans(dat[4:6])) 
を取得し、ベクトルD、Eから行するための手段

列の名前のみがわかっていて、注文ではない場合は、

rowMeans(cbind(dat["a"],dat["b"],dat["c"])) 
rowMeans(cbind(dat["d"],dat["e"],dat["f"])) 

#I dont know how much damage this does to speed but should still be quick 
+0

数百の列を持つデータフレームのために?どのようにこれを一般化することができますか? – Ben

+0

@joran、あなたは正しい、私はあいまいさに残念、私の質問を準備するには急いでいた。タイラー・リンカーの編集には、私が何をしているかを示すコードがあります。 – Ben

5

rowMeansソリューションは速くなりますが、完全を期すために、ここであなたがapplyでこれを行う可能性がある方法ですします:

t(apply(dat,1,function(x){ c(mean(x[1:3]),mean(x[4:6])) })) 
+1

行は、数百の列を持つデータフレーム内の3つの列の連続したセットごとにどういう意味ですか? – Ben

+2

@Benあなたがすでに解決した問題にそれを減らしてください:(1)転置(2)** plyr **または** data.table **を使用してください。 – joran

+0

私はそのショットを出し、上記のタイラーの解決策よりも効率的なものを考え出すことができるかどうかを見てみましょう(ちょっと試してみてください) – Ben

2

::ここにメソッドを満たさないが第二だ

くださいp COLSとサンプルデータのデータフレームは、グループを作成するには、このデータフレームの列の名前を変更し

p <- 99 # how many columns? 
dat <- data.frame(matrix(rnorm(4*p), ncol = p)) 

(上記、問題の私の貧弱な例とは異なりTylerRinkerの答え@以下)現実的なデータセットをシミュレートしますnの連続した列なので、3つの列のグループに興味があるなら、1,1,1,2,2,2,3,3,3などのような列名を取得するか、4列のグループそれは1,1,1,1,2,2,2,2,3,3,3,3などとなります。私は今のところ3つになります(これは私のような人々のための索引作成の一種です

n <- 3 # how many consecutive columns in the groups of interest? 
names(dat) <- rep(seq(1:(ncol(dat)/n)), each = n, len = (ncol(dat))) 

今のメインの欠点は、元のデータの列名があること、適用使用して行を取得するtapplyはグループ

dat.avs <- data.frame(t(apply(dat, 1, tapply, names(dat), mean))) 

の各手段)インデックスについてあまり知らない人置き換えられました(しかし、これは、グループ番号をne列名ではなくw行)、列名が有効な順番でapply-tapply関数によって返されるようにします。あなたの迅速かつ患者の努力のためにみんな

p <- 99 # how many columns? 
dat <- data.frame(matrix(rnorm(4*p), ncol = p)) 
dat.t <- data.frame(t(dat)) 

n <- 3 # how many consecutive columns in the groups of interest? 
dat.t$groups <- as.character(rep(seq(1:(ncol(dat)/n)), each = n, len = (ncol(dat)))) 

library(data.table) 
DT <- data.table(dat.t) 
setkey(DT, groups) 
dat.av <- DT[, lapply(.SD,mean), by=groups] 

ありがとう:@のjoranの提案にさらに

は、ここにdata.tableソリューションです!

+2

'lapply(.SD、mean)'イディオムがv1.8.1では、i)[この質問](http://stackoverflow.com/questions/10584993/r-loop-over-columns-in-data-table)とii)自動.internal() 'mean()'のisation(wikiポイント3はもはや必要ありません)。また、 '.Scdols 'はしばしば便利ですが、ここでは必要ありません。 –

+0

@MatthewDowleあなたの注意に感謝します!私が慣れ親しんだ人ではなく、 '.SDcols'について知っていて嬉しいです。 – Ben

6

@david:averaging every 16 columns in r(今は閉じている)と同様の質問がありました。これは、@ TylerRinkerの答えを@joranと@Benの提案に従って調整して回答しました。結果として得られる関数はOPや今後の読者に役立つかもしれないので、OPのデータの例とともに、ここでその関数をコピーしています。

その後
# Function to apply 'fun' to object 'x' over every 'by' columns 
# Alternatively, 'by' may be a vector of groups 
byapply <- function(x, by, fun, ...) 
{ 
    # Create index list 
    if (length(by) == 1) 
    { 
     nc <- ncol(x) 
     split.index <- rep(1:ceiling(nc/by), each = by, length.out = nc) 
    } else # 'by' is a vector of groups 
    { 
     nc <- length(by) 
     split.index <- by 
    } 
    index.list <- split(seq(from = 1, to = nc), split.index) 

    # Pass index list to fun using sapply() and return object 
    sapply(index.list, function(i) 
      { 
       do.call(fun, list(x[, i], ...)) 
      }) 
} 

、反復試験の平均見つける:

byapply(dat, 3, rowMeans) 

または、反復のおそらく標準偏差:

byapply(dat, 3, apply, 1, sd) 

を更新

byすることができますgrのベクトルとして指定することもできますoups:

byapply(dat, c(1,1,1,2,2,2), rowMeans) 
+0

+1ありがとう、これはまた役に立ちます。 – Ben

0

あなたは組合せ論として知られているものの中に、列の一意の組合せに関数を適用することに興味があるならば、美しくシンプルなソリューションがあります。

combinations <- combn(colnames(df),2,function(x) rowMeans(df[x])) 

だけ動作が速く、上記使用applyファミリー関数としてループ、よりしたがってベクトル化され、3に2を変更し、3つの列、等のすべてのユニークな組み合わせのために統計を計算します。列の順序が重要な場合は、順序集合を再現するように設計された置換アルゴリズムが必要です。combinat::permn

+0

「注文が重要な場合」とは何ですか?combinat :: permn関数は何ですか?コードを編集できますか? – user3495945

+0

組み合わせは並べ替えと同じではありません:https://www.youtube.com/watch?v=s2W6Bce_T30入力の順序が重要な場合は、それが順列です。この場合、「順序」は列の順序を参照します。 –

関連する問題