2013-08-16 1 views
5

요인 열만있는 주어진 데이터 프레임에 대해 최대 m 개의 속성에 대한 모든 조합을 나열하려면 데이터에이 표시되지 않습니다. 다음은 간단한 예입니다 :데이터 프레임에서 관측치가없는 모든 요소 (상호 작용)의 조합을 지정된 차원까지 중복 제거합니다.

d <- expand.grid(w=factor(1:2), x=factor(1:2), y=factor(1:2), 
       z=factor(1:2)) 

# These combinations are removed by tail(): 
rmcomb <- 5; head(d, rmcomb) 

## w x y z 
## 1 1 1 1 1 
## 2 2 1 1 1 
## 3 1 2 1 1 
## 4 2 2 1 1 
## 5 1 1 2 1 


d <- tail(d, -rmcomb) 
ftable(d, row.vars=c("w", "x")) 

##  y 1 2 
##  z 1 2 1 2 
## w x   
## 1 1 0 1 0 1 
## 2 0 1 1 1 
## 2 1 0 1 1 1 
## 2 0 1 1 1 

m == 3을 위해, 우리는 d에서 3 속성 4 + 6 + 4 = 14 개 조합을 고려

m <- 3 
library(plyr) 
llply(
    1:m, 
    function(i) combn(ncol(d), i, simplify=F) 
) -> cc 
unlist(cc, recursive=F) -> cc 
length(cc) 

## [1] 14 

우리는 현재의 선택된 열을 집계 할 수 있습니다 tableuse which를 사용하여 데이터를 제로로 항목을 찾을 수 있습니다 :

그러나
llply(
    cc, 
    function(cols) { 
    which(table(d[, cols]) == 0, arr.ind=T) -> z 
    colnames(z) <- names(d)[cols] 
    if (nrow(z) > 0) list(z) else NULL 
    } 
) -> zz 
unlist(zz, recursive=F) 

## [[1]] 
## y z 
## 1 1 1 
## 
## [[2]] 
## w x z 
## 1 1 1 1 
## 
## [[3]] 
## w y z 
## 1 1 1 1 
## 2 2 1 1 
## 
## [[4]] 
## x y z 
## 1 1 1 1 
## 2 2 1 1 

항목을 위의 결과에서및 [[4]][[1]] (= y == 1, 관측치 없음, z == 1) 항목에서 다루기 때문에 중복됩니다. 솔루션은 따라서 (y,z) == (1,1); (w,x,z) == (1,1,1)이어야합니다.

적은 수의 코딩으로 문제를 해결할 수있는 중복 기능 (= 덮음) 튜플을 제거하는 등의 기능이 내장되어 있습니까? 그렇지 않다면 위의 코드에서 중복 된 항목을 어떻게 제거 하시겠습니까?

+1

... Ferdinand.kraft @ –

+1

: 귀하의 의견 주셔서 감사합니다. 당신에게 불명확 한 점은, 어떻게 질문을 개선 할 수 있습니까? – krlmlr

답변

3

다음은 알 고가 그 서열을 찾아내는 방법입니다. 이제

m = as.matrix(rbind.fill(lapply(zz, as.data.frame))) 
#  y z w x 
#[1,] 1 1 NA NA 
#[2,] NA 1 1 1 
#[3,] 1 1 1 NA 
#[4,] 1 1 2 NA 
#[5,] 1 1 NA 1 
#[6,] 1 1 NA 2 

의를 보자. 먼저 당신이뿐만 아니라 목록 작업을 할 수 있습니다 내가 다루는이 쉽게 찾을 수의가 NA의 기입과, 매트릭스에 목록을 변환 할 수 있습니다,하지만 난 어떤 노력과 확신 subseq에 의해 주어진 행렬의 각 행은 seq의 "서브는"이미 영업 이익의 정의에 따라 seq에 의해 덮여 의미하는 경우 알려되는 기능을 소개 :

is.subsequence = function(seq, subseq) { 
    comp = seq == t(subseq) 

    rowSums(t(is.na(comp) == is.na(seq) & 
      matrix(!(comp %in% FALSE), nrow = length(seq)))) == length(seq) 
} 

만하면 남은 반복하는 것입니다 행렬을 만들고 덮여 진 시퀀스를 버린다.OP에서 자동으로 배열 된 zz 때문에 위에서 아래로이 작업을 수행 할 수 있습니다.

i = 1 
while(i < nrow(m)) { 
    m = rbind(m[1:i,], tail(m, -i)[!is.subsequence(m[i,], tail(m, -i)),]) 

    i = i+1 
} 

m 
#  y z w x 
#[1,] 1 1 NA NA 
#[2,] NA 1 1 1 

그리고 만약 당신이 좋아하면, 당신은 다시 목록에 갈 수 있습니다 :

너무 혼란
apply(m, 1, na.omit) 
+0

NA 값의 행렬을 가진 아이디어는 달콤하다. 결코 그것에 대해서 생각하지 않을 것이다. 나는'issequence'가 벡터화되어있는 것을 이해한다. 그래서'while' 루프가 충분합니까? – krlmlr

+1

@krlmlr 예, 단일 패스를 허용하도록 벡터화되었습니다. – eddi

2

데이터가 잠재적으로 희박하고 m이 너무 작지 않은 경우 (예 : m = 5 이상), 데이터에 나타나지 않는 많은 조합의 값이있을 수 있으며 중복성이 높을 수 있습니다 그래서 생략 된 값 조합의 "약식"집합은 전체 집합보다 현저하게 작습니다. 이 경우 일반적인 프로그래밍 관점에서 재구성하는 것이 더 좋을 수 있으므로 데이터에 나타나지 않는 최대 m 개의 값 (깊이 첫 번째 재귀)의 모든 조합 집합을 재귀 적으로 작성하고 새로운 부재 치 튜플이 생기면 더 이상 재귀하지 않습니다. 이렇게하면 자동으로 출력의 중복을 방지하고 중복 된 튜플을 탐색하지 않아도 시간을 절약 할 수 있습니다. 세트 및/또는 해시 테이블을 사용하면 특정 값 조합이 일정 시간 동안 데이터에 존재하는지 확인할 수 있습니다. 물론 재귀 함수 호출은 c/C++와 비교하여 R과 같은 해석 언어에서 훨씬 느려질 것입니다. 본질적으로 자동으로 원하는 R 패키지를 보지 못했습니다. 따라서 보편적으로 효율적인 솔루션을 원한다면 c/C++와 같은 언어로 전환하는 것이 좋습니다. R c/C++ 통합 프레임 워크를 항상 사용할 수 있습니다. 그래서 귀하의 C/C++ 함수는 R에서 호출 할 수 있습니다.

+0

재귀 알고리즘을 스케치 할 수 있습니까? (xyz)는 (xz), (yz) 또는 (xy)는 말할 것도없고 (x), (y) 또는 (z)도 포함될 수 있기 때문에 부분적으로 보지 않습니다. 또한 일반적인 솔루션에 관심이있는 동안 실제로 m <= 4 일 때, 현재 m == 3으로 작업하고 있습니다. – krlmlr

1

총 값 집합을 알아 내고 이미 데이터에있는 값을 제거하는 방법을 기반으로 한 방법이 있습니다. 분명히 가능성의 전체 세트가 너무 크지 않아야합니다.

d <- expand.grid(rep(list(factor(1:2)), 4)) 
names(d) <- c("w", "x", "y", "z") 

# Remove 5 combinations randomly 
d_miss <- d[-sample(nrow(d), 5), ] 

# To find which ones are missing, build up a complete list 
# (this will be the same as d in this case, but obviously 
# you don't normally have d) 
vals <- lapply(d_miss, unique) 
all_combs <- expand.grid(vals) 

# Now collapse each data frame to a single value, then 
# figure out which ones are missing. There's lots of ways 
# of doing this, this is the approach plyr uses: 
# (you could also use interaction, or paste the values together) 
all <- plyr::id(all_combs) 
some <- plyr::id(d_miss) 

# Here are the missing 
all_combs[setdiff(all, some), ] 
+0

마지막 5 행은 본질적으로'which (table (d_miss) == 0, arr.ind = T)'와 같은 결과를 얻으려면 setNames (as.data.frame (plyr :: unrowname (...)), names (d_miss))를 사용하여 동일한 결과를 얻습니다. 내 코드는'combn'을 사용하여 범주 (= 요소 수준)가 아닌 속성의 조합을 계산하고'which (table (...) 구문은 속성의 각 조합에 적용됩니다 .. 문제는 출력을 압축하는 방법입니다. '(y, z) == (1,1)'을 가진 * 모든 * 값의 조합이 관찰되지 않는다면, 덧붙여 말하면,'(x, y, z) == (1, 1,1)'관찰되지 않는다 – krlmlr

관련 문제