2010-11-29 2 views
53

나는 세 개 이상의 독립 변수를, R 벡터로 표현과 같이 한 :직교 제품 데이터 프레임

A <- c(1,2,3) 
B <- factor(c('x','y')) 
C <- c(0.1,0.5) 

나는 그들 모두의 직교 제품을 가지고 데이터로 결과를 데려 가고 싶다는 이 같은 프레임 :

A B C 
1 x 0.1 
1 x 0.5 
1 y 0.1 
1 y 0.5 
2 x 0.1 
2 x 0.5 
2 y 0.1 
2 y 0.5 
3 x 0.1 
3 x 0.5 
3 y 0.1 
3 y 0.5 

내가 수동으로 rep에 호출을 작성하여이 작업을 수행 할 수 있습니다 :

d <- data.frame(A = rep(A, times=length(B)*length(C)), 
       B = rep(B, times=length(A), each=length(C)), 
       C = rep(C, each=length(A)*length(B)) 

하지만 더 우아한 방법이 있어야합니다. 그렇습니다. product in itertools은 작업의 일부를 수행하지만 반복자의 출력을 흡수하여 데이터 프레임에 넣을 수있는 방법을 찾을 수 없습니다. 어떤 제안?

p.s. 이 계산의 다음 단계는 한 번에 두 단계를 할 수있는 방법을 알고있는 경우

d$D <- f(d$A, d$B, d$C) 

같은, 그 또한 도움이 될 것 같습니다.

+0

함수 f가하는 것을 지정하면 유용 할 것입니다. – Ramnath

+0

'f'는 몇 가지 다른 털이 많은 수학 계산 중 하나의 자리 표시 자입니다. 그러나이 질문의 목적 상, 여러분이 알아야 할 것은 N 개의 적절한 벡터 유형을 가져 와서 하나의 벡터를 생성한다는 것입니다. 모든 입력은 동일한 길이 여야하며 출력도 그 길이입니다. – zwol

+0

이 질문의 제목을 변경하는 것이 좋습니다 ... "데이터 테이블"은 이제 R이 다른 것을 의미합니다. –

답변

57

당신은

편집을 사용할 수 있습니다 : 두 번째 부분을 달성하기 위해 do.call 사용에 대한 대안은 mdply 기능입니다. 여기에 사소한 기능 '붙여 넣기'를 사용하여 사용법을 설명하는 코드

d = expand.grid(x = A, y = B, z = C) 
d = mdply(d, f) 

, 당신은 시도 할 수

d = mdply(d, 'paste', sep = '+'); 
+0

아하! 이 작업을 수행하는 표준 라이브러리 루틴이 있어야한다는 것을 알고 있었지만 호출 된 것을 찾을 수 없었습니다. 누군가에게 2 부에 대한 답변이있을 경우를 대비하여 질문을 공개하겠습니다. – zwol

+0

f가 사용자 정의 함수 인 경우 데이터 프레임을 인수로 허용하고 함수가 구성 요소 벡터로 분할을 처리하도록 수정할 수 있습니다 – Ramnath

+0

plyr 설명서를 보았지만 'mdply '에 대한 것이었다. 감사. – zwol

0

나는 것을 표준 기능 expand.grid을 기억하지 않을 수 있습니다. 여기에 다른 버전이 있습니다.

crossproduct <- function(...,FUN='data.frame') { 
    args <- list(...) 
    n1 <- names(args) 
    n2 <- sapply(match.call()[1+1:length(args)], as.character) 
    nn <- if (is.null(n1)) n2 else ifelse(n1!='',n1,n2) 
    dims <- sapply(args,length) 
    dimtot <- prod(dims) 
    reps <- rev(cumprod(c(1,rev(dims))))[-1] 
    cols <- lapply(1:length(dims), function(j) 
       args[[j]][1+((1:dimtot-1) %/% reps[j]) %% dims[j]]) 
    names(cols) <- nn 
    do.call(match.fun(FUN),cols) 
} 

A <- c(1,2,3) 
B <- factor(c('x','y')) 
C <- c(.1,.5) 

crossproduct(A,B,C) 

crossproduct(A,B,C, FUN=function(...) paste(...,sep='_')) 
5

여기 expand.grid의 Ramnath의 제안을 사용하여, 모두를 할 수있는 방법 :

f <- function(x,y,z) paste(x,y,z,sep="+") 
d <- expand.grid(x=A, y=B, z=C) 
d$D <- do.call(f, d) 

참고하는 data.framelist 때문에 "있는 그대로"ddo.call 작품. 그러나 do.calld의 열 이름이 f의 인수 이름과 일치 할 것으로 예상합니다.

+0

'd'는'expand.grid' 호출에 의해서만 정의됩니다 ... – zwol

+0

@Zack : Thanks; 내 답변을 업데이트했습니다. 한 줄짜리는 아니지만'f'를 평가하는 것은'do.call'을 사용하면 각 인수를 타이핑하는 것보다 훨씬 쉽습니다. –

+0

좋은 옛 do.call 트릭. 좋은 사람! – Ramnath

13

이 경우에 도움이되는 dataframe을 조작하는 함수가 있습니다.

데카르트 제품은 특별한 경우 인 반면, 다양한 조인 (SQL 용어로)을 생성 할 수 있습니다.

데이터 프레임을 매개 변수로 사용하기 때문에 먼저 가변 개수를 데이터 프레임으로 변환해야합니다.

그래서 같은 것을 할 것입니다 : 걱정하는

A.B=merge(data.frame(A=A), data.frame(B=B),by=NULL); 
A.B.C=merge(A.B, data.frame(C=C),by=NULL); 

유일한 것은 당신이 묘사 된대로 행이 정렬되지 않습니다 것입니다. 원하는대로 수동으로 정렬 할 수 있습니다.

merge(x, y, by = intersect(names(x), names(y)), by.x = by, by.y = by, all = FALSE, all.x = all, all.y = all, sort = TRUE, suffixes = c(".x",".y"), incomparables = NULL, ...)

"모두 by.x 또는 의해했을 경우.http://stat.ethz.ch/R-manual/R-patched/library/base/html/merge.html

3

은 훌륭한 data.table 사용을 고려한다 : (Y)의 길이가 0 (길이 제로 벡터 또는 NULL) 결과, R로하고, x 및 y "

디테일이 URL이 표시의 직교 생성물 인 표현력 및 속도 라이브러리. 그것은 함께하면, 변환 서브셋 비교적 간단한 균일 구문을 사용하여 가입 관계 많은 plyr 유스 케이스 (기준 관계형 그룹)를 처리한다.

library(data.table) 
d <- CJ(x=A, y=B, z=C) # Cross join 
d[, w:=f(x,y,z)] # Mutates the data.table 

또는 한 줄

d <- CJ(x=A, y=B, z=C)[, w:=f(x,y,z)]