2017-01-25 5 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

데이비드 감사합니다, 나는 아직도 이것의 논리와 조금 싸우고 있지만 작동합니다. 다행히 해결책으로 당신의 대답을 받아 들일 것입니다. – 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 결과, 같은이 :

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

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 

을 준다거나, 당신은 좀 더 복잡 그룹/요약 출력을 허용하는 do를 사용할 수 있습니다. 이것은 data.frames에서 다중 열 복귀 할 수 있도록 설계되어 있지만, 시나리오에 대해 적용 할 수 있습니다 :

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

은 그룹당 하나 개의 라인을 반환

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

참고를 제공합니다. 따라서 원본 항목 당 한 줄을 원하면 원 자료에 조인 (예 : 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