2016-11-03 4 views
1

他の変数が特定の条件を満たしていて、特別な折りたたみ変数を計算している場合に限り、以下のデータセットをId_noで折りたたみたいとします。特定の条件の下でのみデータフレーム内のケースを折りたたむ

df <- structure(list(Id_no = structure(c(1L, 1L, 1L, 2L, 2L, 3L), .Label = c("n1", 
"n2", "n3"), class = "factor"), Band = structure(c(1L, 2L, 3L, 
1L, 2L, 1L), .Label = c("Band 1", "Band 2", "Band 3"), class = "factor"), 
    median = c(252, 191, 107, 130.5, 61.5, 217), sample_size = c(19L, 
    20L, 1L, 20L, 12L, 1544L)), .Names = c("Id_no", "Band", "median", 
"sample_size"), class = "data.frame", row.names = c(NA, -6L)) 

> df 
    Id_no Band median sample_size 
1 n1 Band 1 252.0   19 
2 n1 Band 2 191.0   20 
3 n1 Band 3 107.0   1 
4 n2 Band 1 130.5   20 
5 n2 Band 2 61.5   12 
6 n3 Band 1 217.0  1544 

崩壊変数はバンド1における中央値の比であるVSこれは実際B1と少なくとも一つの双方のエントリを有することId_noについて計算される2,3

帯域間の中央値を意味しますB2またはB3の

さらに、B2とB3の中央値は、サンプルサイズが> = 10の場合にのみ考慮する必要があります。

私が探している結果の表は、このです:

Id_no b1_vs_rest 
1 n1  1.32 
2 n2  2.12 

最初のステップは、サンプルサイズが最小を満たしていないケースを削除するには、おそらくです:

df <- subset(df, sample_size >=10) 

答えて

1

一つのアプローチ:

library(dplyr) 
res <- df %>% group_by(Id_no) %>% 
       filter(sample_size >= 10) %>% 
       summarise(b1_vs_rest=median[Band == "Band 1"]/mean(median[Band != "Band 1"])) %>% 
       filter(!is.nan(b1_vs_rest)) 

注:dplyr

  1. sample_sizeグラムで行のみを維持するための最初のfilter10以上。
  2. 次にgroup_byId_nosummariseとは、分子のすべての他のバンドのための中央値Band == "Band 1"および分母のためmedianId_noを選択するための比を計算します。
  3. "Band 1"でも"Band 2"も存在しない場合、meanNaNを返し、結果もNaNになります。だから、私たちはfilterの値をもう一度0以外に保つようにしています。NaN

期待どおりのデータを使用した結果は次のとおりです。ここで

print(res) 
### A tibble: 2 x 2 
## Id_no b1_vs_rest 
## <fctr>  <dbl> 
##1  n1 1.319372 
##2  n2 2.121951 
+0

申し訳ありませんが、あなたは少し質問に誤解しました。 b1_vs_restは、B1の中央値で、B2とB3の平均中央値以上である必要があります。 Id_no = n1の場合、B3のsample_sizeは<10なので除去されるので、b1_vs_rest = B1/B2であるため、図はulfelder解と同じです。しかし、sample_sizeが10より大きい場合、数値は異なります。 – Mihael

+0

この部分を次のように修正しました: 'b1_vs_rest = f(median [Band ==" Band 1 "])/ mean(c(f(median [Band ==" Band 2 "])、f(median [Band == "Band 3"]))) 'となりましたが、値は2倍になります。何か案は? – Mihael

+0

@ミアエル:あなたが正しいことが分かります。私の編集を見てください。 – aichao

1

はここソリューションですdplyrif...elseのコンストラクトを使用して、条件によって出力を変えます。あなたの質問(あなたの期待した結果ではない)について、私はあなたが3つのすべてを持っている場合にバンド2と3のメジアンの平均に対するバンド1の中央値の比率を望んでいると仮定しています。

d2 <- df %>% 
    filter(sample_size >= 10) %>% 
    group_by(Id_no) %>% 
    summarise(b1_vs_rest = if(any(Band == "Band 2") & any(Band == "Band 3")) { 
          median[Band == "Band 1"]/(mean(c(median[Band == "Band 2"], median[Band == "Band 3"]))) 
         } else if(any(Band == "Band 2")) { 
          median[Band == "Band 1"]/median[Band == "Band 2"] 
         } else if(any(Band == "Band 3")) { 
          median[Band == "Band 1"]/median[Band == "Band 3"] 
         } else { 
          NA 
         }) %>% 
    filter(!is.na(b1_vs_rest)) 

結果:dplyrを使用して

> d2 
# A tibble: 2 × 2 
    Id_no b1_vs_rest 
    <fctr>  <dbl> 
1  n1 1.319372 
2  n2 2.121951 
+0

ありがとうございます。あなたのコードはこの例でうまくいきますが、実際のデータで試してみると、次のエラーが出ます:eval(substitute(expr)、envir、enclos)のエラー: 'closure'型のオブジェクトはサブセット化できません。 .. あなたはなにか考えはありますか?明らかに、対応する変数名を置き換えました。 – Mihael

+0

あなたの実際のデータがなくてもテストするのは難しいです。おそらく、データフレームや列の名前の違いに関する問題です。あなたが最初のパイプだけで始まり、1つのパイプを段階的に追加すると、どのポイントで失敗するのですか? – ulfelder

1

data.tableを使用してオプションです。 'data.frame'を 'data.table'(setDT(df))に変換し、 'long'から 'wide'(dcast)に変更し、NA行(na.omit)を削除し、.SDcolsを 'Band'列として指定し、最初の列(.SD[[1]])を他の列の合計(Reduce(`+`, ...))で置き換えて、期待される出力を得ます。

library(data.table)#1.9.7+ 
na.omit(dcast(setDT(df)[sample_size >= 10], Id_no~Band, value.var = "median"))[, 
    .(Id_no, b1_vs_rest = .SD[[1]]/Reduce(`+`, .SD[, -1, with = FALSE])) , .SDcols = -1] 
# Id_no b1_vs_rest 
#1: n1 1.319372 
#2: n2 2.121951 
+0

私はあなたのコードをテストしていませんが、最新のdevelバージョンは 'with = FALSE'をもう必要としません –

+0

実際、' with = FALSE'で元の答えを使用していたのは、正しい結果、aichaoの解決策のものと一致 – Mihael

+0

@Mihael私はdevelバージョンを使用していました。私はそれが何か違いがあるかどうかわからない – akrun

関連する問題