2017-01-25 12 views
-1

dplyrでは、前に選択したグループに対して条件付き関数を適用したいと考えています。ただし、関数は常に完全なデータに対して計算されます。最小限の例:dplyrのグループ化と関数

func_a = function(data_a) { 
    value = mean(data_a$V2) 
    return(value) 
} 

data = as.data.frame(cbind(c("a","a","a","b","b","b"), c(1,2,3,4,5,6))) 
data$V2=as.numeric(data$V2) 
data 
V1 V2 
a 1 
a 2 
a 3 
b 4 
b 5 
b 6 
o = data %>% group_by(V1) %>% dplyr::mutate(test = func_a(.)) 

o$test 
[1] 3.5 3.5 3.5 3.5 3.5 3.5 
私が期待しているだろう

/希望:

[1] 2 2 2 5 5 5 

平均機能がプリミティブ一例であり、dplyr::mutate(test = mean(V2))が仕事をするだろう、明らかに。しかし、そのように使用できない他の機能があります。

この質問の主なポイントは、データフレームのスライスを全体の関数ではなく関数に転送する方法です。

+0

を与え、次のように適用することができない機能があるので、はい、それは必見です。 – MaHo

+3

関数を誤って記述しました。それは 'func_a = function(x)mean(x)'のようなものでなければならず、 'data%>%group_by(V1)%>%mutate(test = func_a(V2))'を使って、あなたがあなたにそれを伝えなくても 'V2'で実行させたいのでない限り、すべてのcols' data%>%group_by(V1)%>%mutate_all(funs(func_a)) 'その場合、おそらく 'lazyval'パッケージを使いこなす必要があります。 –

+0

Davidさん、ありがとう、私はまだこれの論理で少し戦っていますが、それは動作します。幸いにも、私はあなたの答えを解決策として受け入れます。 – MaHo

答えて

1

@DavidArenburgがコメントしたように、あなたの関数の仕方は、dplyrがどのように動作するように設計されているのではありません。 .は、完全変数(この場合はdata.frame)が%>%を通過することを明示的に意味します。私はこのデータを全面的に何かしたいときにこのハックを使いました。

data %>% 
    group_by(V1) %>% 
    mutate(eg = mean(V2)/mean(.$V2)) 

は、グループ化を適用するmutateを取得するため

 V1 V2  eg 
    <fctr> <dbl>  <dbl> 
1  a  1 0.5714286 
2  a  2 0.5714286 
3  a  3 0.5714286 
4  b  4 1.4285714 
5  b  5 1.4285714 
6  b  6 1.4285714 

、最適なソリューションを提供し、

func_forColumn = function(data_a) { 
    value = mean(data_a) 
    return(value) 
} 

data %>% 
    group_by(V1) %>% 
    mutate(test = func_forColumn(V2)) 

を与え、例えば、代わりに列名(複数可)を渡すことです
 V1 V2 test 
    <fctr> <dbl> <dbl> 
1  a  1  2 
2  a  2  2 
3  a  3  2 
4  b  4  5 
5  b  5  5 
6  b  6  5 

完全なdata.frameを渡すことができる必要があります(たとえば、古いパラダイムの関数を使って作業していて何らかの理由でそれらを更新できないなど)場合は、慣れたと仮定してsplit/lapply 、そしてちょうどbind_rows結果、そのような:あなたはやや複雑グループ/要約出力を可能にdoを使用することができます

V1 V2 test 
1 a 1 2 
2 a 2 2 
3 a 3 2 
4 b 4 5 
5 b 5 5 
6 b 6 5 

かを、与え

data %>% 
    split(.$V1) %>% 
    lapply(function(x){ 
    x %>% 
     mutate(test = func_a(.)) 
    }) %>% 
    bind_rows() 

。これはdata.framesに複数列のリターンを許可するように設計されていますが、あなたのシナリオに適合させることができます。

data %>% 
    group_by(V1) %>% 
    do(as.data.frame(func_a(.))) 

は、それが唯一のグループごとに1つの行を返すこと

 V1 `func_a(.)` 
    <fctr>  <dbl> 
1  a   2 
2  b   5 

注意を与えます。したがって、元のエントリごとに1行が必要な場合は、元のデータに結合(例:left_join)を使用する必要があります。

doのより一般的な使用例があります。これは、関数が完全なdata.frameを最初に期待している理由とより密接に関連している可能性があります。

mySummary <- function(x){ 
    as.data.frame(rbind(summary(x))) 
} 

data %>% 
    group_by(V1) %>% 
    do(mySummary(.$V2)) 

が書かれたよう

 V1 Min. `1st Qu.` Median Mean `3rd Qu.` Max. 
    <fctr> <dbl>  <dbl> <dbl> <dbl>  <dbl> <dbl> 
1  a  1  1.5  2  2  2.5  3 
2  b  4  4.5  5  5  5.5  6 
関連する問題