科学の箱

科学・IT・登山の話題

R

データフレームで層別に操作をする

投稿日:

Rでデータベースに似たデータを取り扱う際には、データフレームを使うことがおおい。JavaはPHPなどのプログラミング言語では、層別に集計作業をする際にはデータベース上のSQLか、データを読み込んでから、ループを使って集計作業をする。

Rではデータフレームに対してサブセットやby()を適用して簡単に層別集計作業を実行できる。この記述方法はR独特であり、慣れるまでは間違いも多いし、記述にもとまどう。また同じ結果を戻すことができる記述方法も複数ある。

boneデータを利用して層別集計作業の記述方法をまとめておく。bone$spnbmdに対してcut()を実行してあらかじめカテゴリに分ける。

> bone$age_cat <- cut(bone$age, breaks=seq(9, 26, 1), right=FALSE, ordered_result=TRUE)
> head(bone)
  idnum   age gender      spnbmd age_cat
1     1 11.70   male 0.018080670 [11,12)
2     1 12.70   male 0.060109290 [12,13)
3     1 13.75   male 0.005857545 [13,14)
4     2 13.25   male 0.010263930 [13,14)
5     2 14.30   male 0.210526300 [14,15)
6     2 15.30   male 0.040843210 [15,16)
|

次にage_catごとにspnbmdの平均値を求める。まずbyを利用してみる。

> by(bone$spnbmd, bone$age_cat, mean)
bone$age_cat: [9,10)
[1] 0.04363858
--------------------------------------------------------- 
bone$age_cat: [10,11)
[1] 0.05542119

byは第一パラメータに集計作業の対象となる項目、第二パラメータが層別の項目、第三パラメータが処理をする関数となる。上記の例ではbone$spnbmdに対してmean()関数を適用する。その際にbone$age_catで層別するように指示している。

今回は処理の対象をベクトルとしたがデータフレームにすることも可能である。この場合処理の内容もデータフレームを対象とする関数を指定する。

> by(bone, bone$age_cat, summary)
bone$age_cat: [9,10)
     idnum            age           gender      spnbmd            age_cat  
 Min.   :  9.0   Min.   :9.400   female:8   Min.   :0.003827   [9,10) :12  
 1st Qu.:110.8   1st Qu.:9.688   male  :4   1st Qu.:0.016003   [10,11): 0  
 Median :268.0   Median :9.800              Median :0.026558   [11,12): 0  
 Mean   :234.8   Mean   :9.750              Mean   :0.043639   [12,13): 0  
 3rd Qu.:368.8   3rd Qu.:9.800              3rd Qu.:0.073463   [13,14): 0  
 Max.   :384.0   Max.   :9.950              Max.   :0.100025   [14,15): 0  
                                                               (Other): 0  
--------------------------------------------------------- 
bone$age_cat: [10,11)
     idnum            age           gender       spnbmd            age_cat  
 Min.   :  4.0   Min.   :10.00   female:15   Min.   :-0.04276   [10,11):27  
 1st Qu.: 59.0   1st Qu.:10.18   male  :12   1st Qu.: 0.02709   [9,10) : 0  
 Median :127.0   Median :10.55               Median : 0.04810   [11,12): 0  
 Mean   :156.7   Mean   :10.47               Mean   : 0.05542   [12,13): 0  
 3rd Qu.:257.5   3rd Qu.:10.65               3rd Qu.: 0.08445   [13,14): 0  
 Max.   :335.0   Max.   :10.95               Max.   : 0.16695   [14,15): 0  
                                                                (Other): 0

次にaggregate()を使ってみる。

> aggregate(bone$spnbmd, mean, by=list(bone$age_cat))
   Group.1             x
1   [9,10)  0.0436385764
2  [10,11)  0.0554211933
3  [11,12)  0.0643080464
4  [12,13)  0.0840868598
5  [13,14)  0.0750408580

aggregate()には第一パラメータに集計対象フィールド(bone$spnbmd), 第二パラメータが処理、byにカテゴリを指定する。

aggregateの別の書き方もある。下記の例ではformuralを利用する。利点としてはlevels()を使わないので記述がすっきりしているのと、levels()の処理時間分、短縮される。

> aggregate( spnbmd~age_cat, bone, mean)
   age_cat        spnbmd
1   [9,10)  0.0436385764
2  [10,11)  0.0554211933
3  [11,12)  0.0643080464
4  [12,13)  0.0840868598
5  [13,14)  0.0750408580

spnbmd~age_catがformulraとなる。第二パラメータにデータソースとなるboneデータフレーム、第三パラメータが処理関数となる。

フォーミュラについては直感で理解するのが難しい。下記に説明が載っている。

  • http://www.dummies.com/how-to/content/how-to-use-the-formula-interface-in-r.html
  • http://lamages.blogspot.jp/2012/01/say-it-in-r-with-by-apply-and-friends.html

次にsapplyを利用してみる。

> sapply(split(bone$spnbmd, bone$age_cat),mean)
       [9,10)       [10,11)       [11,12)       [12,13)       [13,14) 
 0.0436385764  0.0554211933  0.0643080464  0.0840868598  0.0750408580 
      [14,15)       [15,16)       [16,17)       [17,18)       [18,19) 
 0.0584768210  0.0438216449  0.0273783762  0.0200704395  0.0086980910 
      [19,20)       [20,21)       [21,22)       [22,23)       [23,24) 
 0.0100798970  0.0065388599 -0.0054547589  0.0039951198 -0.0004379415 
      [24,25)       [25,26) 
-0.0022293219  0.0170577215

この式ではsplit()でage_catで層別にしたbone$spnbmdをまず出力する。split()の出力結果はリストになっている。

> str(split(bone$spnbmd, bone$age_cat))
List of 17
 $ [9,10) : num [1:12] 0.03137 0.06546 0.10003 0.01585 0.00383 ...
 $ [10,11): num [1:27] 0.10804 0.029 0.00193 0.12197 0.01484 ...
 $ [11,12): num [1:46] 0.0181 -0.0296 0.2199 -0.0061 0.0334 ...

Rではリストの各成分に対してlapply関数で処理を適用できる。その結果層別の平均が求められている。

リストとデータフレームの違いについては以下が詳しい。

https://sites.google.com/site/leihcrev/r/lists-and-data-frames

tapply()は層別に集計するために用意された関数である。

> tapply(bone$spnbmd, bone$age_cat, mean)
       [9,10)       [10,11)       [11,12)       [12,13)       [13,14) 
 0.0436385764  0.0554211933  0.0643080464  0.0840868598  0.0750408580 
      [14,15)       [15,16)       [16,17)       [17,18)       [18,19)

第二パラメータにはfactor化された変数を指定する。

メタ情報

inarticle



メタ情報

inarticle



-R
-

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

no image

oneway.test, aov, anovaの違い-2

さてoneway.test, aov, anovaの違いをもとにしてそれぞれの関数について調べてみる。 機能 advantage disadvantage oneway.test 分散分析 等分散を仮 …

no image

findFn{sos}

findFn{sos} findFn(string, maxPages = 20, sortby = NULL, verbose = 1, …) 文字列から関数を探すことができる。パッケー …

no image

dataanalysis-002-week4

クラスタリング SVDと組み合わせることでよりクラスに分かれているクラスタリングを実行できる。 散布図でクラスタリングする変数を探す クラスタリング SVDを実行する SVDの結果をクラスタリングに取 …

no image

Rオブジェクト指向のメモ

whichではwhich.minとwhich.maxが用意されているという指摘を受けたので調べ見てた。 which.minとwhich.maxはRでいうところのオブジェクト指向を利用した構造にみえる。 …

no image

ジニ係数(再掲)

ジニ係数について修正した。とりあえずコード。 revenue<-read.csv(file=”data.csv”, head=TRUE) revenue$TotalRevenues_n < …

2014年4月
« 3月   5月 »
 123456
78910111213
14151617181920
21222324252627
282930  

side bar top



アーカイブ

カテゴリー