2017-11-14 1 views
2

"2 열"쌍인 a1 ... n 및 c1 ... n 시리즈를 기반으로 간단한 빼기를 만들고 싶습니다. dplyr에서 78 쌍 이상의 세 번째 열 b1 ... n을 작성합니다. 그러나 열을 올바르게 호출하는 방법과 각 열 쌍에 대해 행을 처리하는 방법을 알지 못합니다.78 * 2 다른 변수의 열 입력을 기반으로 새 (78) 변수를 계산합니다. dplyr

df 
var C400.0 C403.7 C407.1 A399.6 A403.4 A406.4 
V1 1.176 1.149 1.111 0.767 0.736 0.699 
V2 1.192 1.160 1.127 0.770 0.738 0.707 
V3 1.223 1.1918 1.154 0.775 0.744 0.715 

나는 시도했다 : 어떤 성공

b_names <- c("B400", "B403", "B407") 
df_b <- mutate_at(df,vars(C400.0:C407.1), .funs(b_names= ., vars(C400.0:C407.1)-vars(A399.6:A403.4))) 

결과는 다음

df_b 
var C400.0 C403.7 C407.1 A399.6 A403.4 A406.4 B400 B403 B407 
V1 1.176 1.149 1.111 0.767 0.736 0.699 0.408 0.412 0.412 
V2 1.192 1.160 1.127 0.770 0.738 0.707 0.421 0.421 0.420 
V3 1.223 1.1918 1.154 0.775 0.744 0.715 0.447 0.447 0.439 
+3

열 이름으로 인코딩 된 값없이 긴 형식으로 데이터를 가져옵니다. 'tidyr :: gather' 또는'reshape2 :: melt'이 도움이 될 것입니다. – Gregor

+1

아니면 그냥 base :'cbind (df, setNames (df [2 : 4] - df [5 : 7], b_names))'로 위치를 정하십시오. 모든 것이 올바른 순서로 이루어 졌는지 확인하십시오. – Gregor

+0

제가 reshape2 및 tidyr 여러 열을 녹여하지 않는 것 같아 ..? data.table을 사용하면 패턴 헬퍼 함수'data.table (df) %> % melt (meas = patterns ("A", "C"), value를 사용할 수 있습니다.이름 = C를 ("A", "C")) %> % 돌연변이 (B = C - A) '하는 대신'mapply'과'assign'의 – Frank

답변

1

과 같아야 긴 형식으로 데이터를 정리 처음에 기초한 tidyverse 솔루션입니다 .

# load packages 
require(stringr) 
require(tidyverse) 

# your example data 
df <- read_table('var C400.0 C403.7 C407.1 A399.6 A403.4 A406.4 
V1 1.176 1.149 1.111 0.767 0.736 0.699 
V2 1.192 1.160 1.127 0.770 0.738 0.707 
V3 1.223 1.1918 1.154 0.775 0.744 0.715') 

# generating obtained values 
df %>% 
    gather(col, value, -var) %>% 
    mutate(col_letter = str_extract(col, 'A|C')) %>% 
    group_by(var, col_letter) %>% 
    mutate(col_position = row_number()) %>% 
    group_by(var) %>% 
    select(-col) %>% 
    spread(col_letter, value) %>% 
    mutate(dif = C - A) %>% 
    select(var, col_position, dif) %>% 
    spread(col_position, dif, sep='_') %>% 
    bind_cols(df, .) 

출력에 원하는 열 이름이 없지만 요청한 모든 값이 포함되어 있습니다. 원할 경우이 시점에서 수동으로 이름을 바꿀 수 있습니다.

1

이 솔루션은 dplyr을 사용하지 않지만 원하는 것을 성취합니다.

library(readr) 
df <- read_table('var C400.0 C403.7 C407.1 A399.6 A403.4 A406.4 
V1 1.176 1.149 1.111 0.767 0.736 0.699 
V2 1.192 1.160 1.127 0.770 0.738 0.707 
V3 1.223 1.1918 1.154 0.775 0.744 0.715') 

어떤 불쾌한 부작용 버전 (또한 반복하지, 모든 벡터화는)

이 그레고르 덕분입니다. 내가 그들을 의도적으로 할 때 나는 부작용을 신경 쓰지 않지만, 모든 사람이 같은 방법 :

library(stringr) 
cNames = grep("^C",names(df),value=T) 
aNames = grep("^A",names(df),value=T) 

newCols = df[cNames]-df[aNames] 
setNames(newCols, paste0("B", str_extract(cNames, "[0-9]+"))) 
#Alternative solution that doesn't require the stringr library 
#setNames(newCols, paste0("B", sub(".*?([0-9]+).*","\\1",cNames))) 
df = cbind(df,newCols) 

먼저 우리가 'C'이름과 'A'이름을 추출을 느낀다. 이것은 이미 주문되었다고 가정합니다. 그러나 질문에서 보여준 결과로 인해 A406.4가 C403.7과 어떻게 일치하는지 명확하게 알 수 없습니다.

그런 다음 열 이름을 기준으로 df의 하위 집합을 만들고 결과 하위 집합 data.frames의 요소 별 빼기를 수행 할 수 있습니다. 우리는 이름을 바꾸고 간단한 cbind을합니다. 원액

mapply(function(x,y){ 
    num = str_extract(x,"[0-9]+") 
    df[[paste0("B",num)]] = df[[x]]-df[[y]] 
    assign("df",df,envir=globalenv()) 
    return(NULL) 
},cNames,aNames) 

그러면 I는 두 개의 입력을 취하는 함수를 작성하고 'C'및 이름 'A'이름의 세트를 통해 루프 mapply 사용. 각 조합에서 'C'이름의 번호를 추출하여 'B'에 붙이고 'C'- 'A'의 차이를 지정합니다. 그런 다음 일련의 새 열을 만들기 때문에 df을 글로벌 환경 (큰 오래된 부작용)으로 다시 지정합니다. mapply는 NULL 값을 반환하지만 df는 B 열을 포함하도록 업데이트되었습니다. 이렇게하면 원래의 광범위한 데이터 구조가 그대로 유지됩니다. tidyverse

+1

, 당신이 단지 수'new_cols = DF [CNAMES] - 안양 [aNames]'한꺼번에 이름을 설정'setNames (new_cols, paste0 ("B", str_extract (CNAMES "[0-9] +"))) ','마지막 결과 = cbind (DF, new_cols) '. 루프가 필요 없음/적용 필요, 벡터화, 불쾌한 부작용 없음. – Gregor

+0

@ 그레고 감사합니다. 분명히 나는 ​​그것에 대해 생각하지 않았습니다. 당신의 벡터화 된 솔루션을 추가했습니다. – Mark

+0

또 하나의 (작은) 제안 - 당신이'aNames'와'cNames'에 대한'grep' 이미있어 이후, 당신은 또한 새로운 열의'대신 str_extract''의 grep'를 사용하여 완전히'stringr' 의존성을 죽일 수 이름. – Gregor