質問
できるようになりたいです summarize
グループ化されたデータ フレーム。どの変数が存在するかは必ずしもわかりませんが、各変数が存在する場合にそれをどのように要約するかはわかっています。
次のようなデータフレームがあるとします。
df <- data.frame(id = c(rep('a', 5), rep('b', 8), rep('c', 4)),
var1 = round(runif(17) * 10, 3),
var2 = sample(c(1:4), 17, replace = TRUE),
var4 = sample(1:1000, 17))
> df
id var1 var2 var4
1 a 5.930 4 360
2 a 7.265 2 713
3 a 3.704 3 117
4 a 5.149 2 782
5 a 3.777 2 640
6 b 4.183 2 802
7 b 0.107 2 638
8 b 5.323 4 327
9 b 4.322 2 631
10 b 0.937 3 921
11 b 5.558 2 570
12 b 5.902 4 363
13 b 0.671 3 432
14 c 0.475 1 845
15 c 1.562 3 620
16 c 4.464 2 997
17 c 1.714 2 714
var3 が欠落していることに注意してください。ある場合もあれば、ない場合もあります。存在する場合は常に同じタイプです。どちらの場合もきちんと対応できるようにしたいと思っています。
要約すると、次のように言えます。 id
, の平均値を取得したいです。 var1
, 、の中央値 var2
, 、の中央値 var3
(存在する場合) および最大値 var4
. 。すべての変数が存在する場合は、次のように設定できます。
library('dplyr')
set.seed(111)
result <- df %>% group_by(id) %>%
summarize(var1 = mean(var1),
var2 = median(var2),
var3 = median(var3),
var4 = max(var4))
ただし、以来、 var3
そこに存在しない場合、エラーが発生します。 Error in median(var3) : object 'var3' not found
.
直感的には、次のようなことを試してみます。
result <- df %>% group_by(id) %>%
summarize(if('var1' %in% names(df)) var1 = mean(var1) else NULL,
if('var2' %in% names(df)) var2 = median(var2) else NULL,
if('var3' %in% names(df)) var3 = median(var3) else NULL,
if('var4' %in% names(df)) var4 = max(var4) else NULL)
しかし、明らかにそれはうまくいきません。あるいは、私の直感が少し間違っているのかもしれません。
dplyr を使用してこれをきれいに達成する方法について誰かが提案を持っていますか?ご想像のとおり、 df
実際には、多くの列を含む大きなデータ フレームであり、 var3
欠落している可能性がある任意の数の列のうちの 1 つです。
解決
これは正確な解決策ではありませんが、@joran が提案したように、考えられるすべての列を事前に作成したくない場合はおそらく回避策です。最初に指定したすべての列が作成されますが、そのうちのいくつかは単に NA
. 。その後、apply を使用して列を削除できます。ただし、 names(dd)
, 、内部で使用する場合 dplyr
チェーンでは、同じ操作で作成された列名ではなく、入力 data.frame 内にあった列名のみが認識されます。
dd <- dd %>%
group_by(id) %>%
summarize(var1 = ifelse("var1" %in% names(dd), mean(var1), NA),
var2 = ifelse("var2" %in% names(dd), max(var2), NA))
dd <- dd[,apply(dd, 2, function(x) ifelse(all(is.na(x)), FALSE, TRUE))]
もう 1 つの潜在的な回避策は、 summarise_each
関数ですが、それは、たとえば、すべての列の平均、中央値、最大値が必要かどうかによって決まると思います。
他のヒント
私はあなたがいくつかのステップでこれを行うことができると思います:
-
melt
を使用して幅から長く変換します。
-
dplyr
を使った要約
-
dcast
を使用して長くから広く変換
例えば:
tmp <- melt(df, id.vars="id")
tmp <- tmp %>%
group_by(id, variable) %>%
summarise(mean = mean(value), median = median(value), max = max(value))
tmp <- melt(tmp, id.vars=c("id", "variable"), variable.name="stat")
tmp <- dcast(tmp, id ~ stat + variable)
.
さまざまな変数の平均、中央値、および最大が必要なので、追加のステップを追加しなければなりませんでした。