2017-12-07 21 views
2

최근 학생 점수 데이터 항목 (학생 당 1 행, ID 열 및 여러 정수 값 열, 점수 구성 요소 당 하나씩)을 컴파일해야했습니다. . "마스터"데이터 프레임과 여러 보정 데이터 프레임 (대부분 NA 및 마스터에 대한 일부 업데이트 포함)을 결합하여 마스터의 최대 값과 모든 수정 사항을 결과에 포함시켜야했습니다.dplyr에서 map2()를 사용하여 열 목록을 변경하는 방법

mutate() 호출 시퀀스를 복사하여 붙여 넣는 데 성공했는데 (아래 예제 참조), 내 생각에는 우아하지 않습니다. 내가하고 싶었던 것은 복사하여 붙여 넣기 대신에 map2 행을 따라 무언가를 사용하고 두 개의 열 목록을 사용하여 열을 쌍으로 비교하는 것이 었습니다. 뭔가 (분명히 그런 식으로 작동하지 않습니다) :

list_of_cols1 <- list(col1.x, col2.x, col3.x) 
list_of_cols2 <- list(col1.y, col2.y, col3.y 
map2(list_of_cols1, list_of_cols2, ~ column = pmax(.x, .y, na.rm=T)) 

나는 그것을 할 수 없을 것 같습니다. 내 질문은 : 열의 이러한 목록을 지정하고 파이프에 map2() 전화에서 그들을 돌연변이 방법, 또는 심지어 가능합니다 - 내가 잘못 했어?

최소 동작하는 예제

library(tidyverse) 

master <- tibble(
    id=c(1,2,3), 
    col1=c(1,1,1), 
    col2=c(2,2,2), 
    col3=c(3,3,3) 
) 
correction1 <- tibble(
    id=seq(1,3), 
    col1=c(NA, NA, 2), 
    col2=c(1, NA, 3), 
    col3=c(NA, NA, NA) 
) 

result <- reduce(
    # Ultimately there would several correction data frames 
    list(master, correction1), 
    function(x,y) { 
    x <- x %>% 
     left_join(
     y, 
     by = c("id") 
    ) %>% 
     # Wish I knew how to do this mutate call with map2 
     mutate(
     col1 = pmax(col1.x, col1.y, na.rm=T), 
     col2 = pmax(col2.x, col2.y, na.rm=T), 
     col3 = pmax(col3.x, col3.y, na.rm=T) 
    ) %>% 
     select(id, col1:col3) 
    } 
) 

결과는 행이 다음 요약 바인딩,

> result 
# A tibble: 3 x 4 
    id col1 col2 col3 
    <int> <dbl> <dbl> <dbl> 
1  1  1  2  3 
2  2  1  2  3 
3  3  2  3  3 
+0

명확히하기 위해, 값이 'master'에있는 값보다 큰 경우에만 수정해야합니다. – useR

+0

좋은 질문이지만, 목표는 '마스터'와 '수정 1'(및 '수정 2', '수정 3'등) 테이블에서 최대 가치를 찾는 것입니다. –

답변

0

대신 할보다 left_join입니다. 예를 실제로

result <- reduce(
    list(master, master), 
    function(x,y) { 
    bind_rows(x, y) %>% 
     group_by(id) %>% 
     summarize_all(max, na.rm=T) 
    } 
) 
result 
#  id col1 col2 col3 
# <dbl> <dbl> <dbl> <dbl> 
# 1  1  1  2  3 
# 2  2  1  2  3 
# 3  3  2  3  3 

를 들어, 당신도 다른 테이블을

correction2 <- tibble(id=2,col1=NA,col2=8,col3=NA) 
bind_rows(master, correction1, correction2) %>% 
    group_by(id) %>% 
    summarize_all(max, na.rm=T) 
+0

아, 단순! 저는 열을 비교하는 대신에 행 방향으로 갈 수 있다고 생각조차하지 않았습니다. 이것은 첫 번째 대답이었고 아름답게 간단했습니다. –

0

죄송이 응답하지 않습니다 귀하의 질문에 대한 map2 추가 목록

를 취할 수 bind_rows으로 줄일 필요가 없습니다, I 행에 대해 행보다 집계하는 것이 더 쉬운 것 같습니다. tidy R :

correction 테이블은 항상 master으로 동일한 구조를 가질 것이다
library(dplyr) 

master <- tibble(
    id=c(1,2,3), 
    col1=c(1,1,1), 
    col2=c(2,2,2), 
    col3=c(3,3,3) 
) 
correction1 <- tibble(
    id=seq(1,3), 
    col1=c(NA, NA, 2), 
    col2=c(1, NA, 3), 
    col3=c(NA, NA, NA) 
) 

result <- list(master, correction1) %>% 
    bind_rows() %>% 
    group_by(id) %>% 
    summarise_all(max, na.rm = TRUE) 

result 
#> # A tibble: 3 x 4 
#>  id col1 col2 col3 
#> <dbl> <dbl> <dbl> <dbl> 
#> 1  1  1  2  3 
#> 2  2  1  2  3 
#> 3  3  2  3  3 
0

경우에, 당신은 뭔가를 할 수있는 다음과 같은 :

update_master = function(x, ...){ 
    map(list(x, ...), function(x) as.matrix(x[-1])) %>% 
    reduce(pmax, na.rm = TRUE) %>% 
    data.frame(id = x[[1]], .) 
} 

update_master(master, correction1) 
:

library(dplyr) 
library(purrr) 

update_master = function(...){ 
    map(list(...), as.matrix) %>% 
    reduce(pmax, na.rm = TRUE) %>% 
    data.frame() 
} 

update_master(master, correction1) 

는 문자 값을 다음과 같은 수정을 할 id을 허용하려면

결과 :

id col1 col2 col3 
1 1 1 2 3 
2 2 1 2 3 
3 3 2 3 3