2016-09-13 4 views
6

행에 개인이 하나있는 R의 데이터 프레임이 있습니다. 때로는 개인이 두 줄로 나타나고 중복 된 ID를 기반으로이 줄을 조합하고 싶습니다.R의 데이터 프레임 행을 여러 열을 기준으로 조합하십시오.

각 개인은 여러 개의 ID를 가지고 있으며 ID가 두 번 나타날 때 은 반드시 동일한 열에 나타나지 않습니다. 행 (1)의 ID b 유사하게 3 행의 ID a 동일하기 때문에 2 ID c 같음, 행의 ID a

dat <- data.frame(a = c('cat', 'canine', 'feline', 'dog'), 
        b = c('feline', 'puppy', 'meower', 'wolf'), 
        c = c('kitten', 'barker', 'kitty', 'canine'), 
        d = c('shorthair', 'collie', '', ''), 
        e = c(1, 5, 3, 8)) 

> dat 
     a  b  c   d e 
1 cat feline kitten shorthair 1 
2 canine puppy barker collie 5 
3 feline meower kitty   3 
4 dog wolf canine   8 

그래서 행 1 및 3은 결합되어야한다 : 여기서

는 예시적인 데이터 프레임 행 4의 행이 결합되어야합니다.

이상적인 결과는 다음과 같아야합니다.

 a.1 b.1 c.1  d.1 e.1 a.2 b.3 c.2 d.2 e.2 
1 cat feline kitten shorthair 1 feline meower kitty  3 
2 canine puppy barker collie 5 dog wolf canine  8 

(행이 빈 문자열 ID를 공유를 기반으로 합친되지 않았 음을 유의하십시오.)이 작업을 수행 할 수있는 방법에

내 생각 은 다음과 같습니다,하지만 난 '꽤 확신 잘못된 경로로 향하게되어 문제 해결에 도움이되지 않을 수 있습니다.

각 행에 행 ID를 할당 한 다음 데이터를 녹일 수 있다고 생각했습니다. 그 후, 나는 행을 통해 행을 옮길 수 있었다. ID 중 하나가 이전 행과 일치하는 행을 찾았을 때 (예 : 3 행 ID 중 하나가 1 행 ID 중 하나와 일치하는 경우), 현재 행의 행 ID의 모든 인스턴스를 이전 행 ID와 일치하도록 변경합니다 (예 : 3의 모든 행 ID가 1로 변경됨). 이 방법 두 가지 문제가 있습니다

dat$row.id <- 1:nrow(dat) 
library(reshape2) 
dat.melt <- melt(dat, id.vars = c('e', 'row.id')) 
for (i in 2:nrow(dat.melt)) { 
    # This next step is just to ignore the empty values 
    if (grepl('^[[:space:]]*$', dat.melt$value[i])) { 
    next 
    } 
    earlier.instance <- dat.melt$row.id[which(dat.melt$value[1:(i-1)] == dat.melt$value[i])] 
    if (length(earlier.instance) > 0) { 
    earlier.row.id <- earlier.instance[1] 
    dat.melt$row.id[dat.melt$row.id == dat.melt$row.id[i]] <- earlier.row.id 
    } 
} 

:

여기 내가 사용하고 코드입니다.

  1. 그것은 행 3 일치 행 1의 ID,이 경우에는 5 행 일치 행 3의 다른 ID가 모두 행 3 열 5 행 ID가 1로 변경되어야한다고 할 수있다. 이것은 행을 순차적으로 처리하는 것이 중요하다는 것을 의미합니다. 이는 apply 함수가 아닌 for 루프를 사용하게합니다. 나는 이것이 매우 R 유사하지 않다는 것을 알고 있으며, 큰 데이터 프레임을 가지고 일하고있다. 매우 느리다.
  2. 이 코드는 아래 출력을 생성합니다. row.idvariable이 동일한 행이 여러 개 있으므로 여기에 나온 출력을 얻기 위해 캐스팅하는 방법을 모르겠습니다. 여기서 dcast을 사용하면 집계 함수를 사용해야합니다.

출력 : 여기에

e row.id variable  value 
1 1  3  a  cat 
2 5  2  a canine 
3 3  3  a feline 
4 8  2  a  dog 
5 1  3  b feline 
6 5  2  b  puppy 
7 3  3  b meower 
8 8  2  b  wolf 
9 1  3  c kitten 
10 5  2  c barker 
11 3  3  c  kitty 
12 8  2  c canine 
13 1  3  d shorthair 
14 5  2  d collie 
15 3  3  d   
16 8  2  d   

답변

2

새로운 답변. 약간의 재미 (/ 좌절)이 일을했다. 가장 빠른 솔루션은 아니지만 내 다른 대답이 중단 된 곳을 지나쳐야합니다. 설명해 드리죠 :

dat <- data.table(a = c('cat', 'canine', 'feline', 'dog', 'cat','fido'), 
        b = c('feline', 'puppy', 'meower', 'wolf', 'kitten', 'dog'), 
        c = c('kit', 'barker', 'kitty', 'canine', 'feline','wolf'), 
        d = c('shorthair', 'collie', '', '','',''), 
        e = c(1, 2, 3, 4, 5, 6)) 

dat[, All := paste(a, b,c),] 

두 변경 : dat$e 이제 인덱스 컬럼, 그래서 그것이 중 행의 단지 숫자 위치입니다. 그렇지 않으면 e이 중요한 경우 새 열을 만들어 교체하십시오.

다음은 첫 번째 루프입니다. 이것은 3 개의 새로운 열 FirstMatchingID 등을 만든다. 이것들은 전에와 같다 : 그들은 abc을 위해 dat$All과 가장 일치하는 가장 낮은 (가장 낮은 행 #) 색인을 준다.

for(i in 2:nrow(dat)) { 
    x <- grepl(dat[i]$a, dat[i-(1:i)]$All) 
    y <- max(which(x %in% TRUE)) 
    dat[i, FirstMatchingID := dat[i-y]$e] 

    x2 <- grepl(dat[i]$b, dat[i-(1:i)]$All) 
    y2 <- max(which(x2 %in% TRUE)) 
    dat[i, SecondMatchingID := dat[i-y2]$e] 

    x3 <- grepl(dat[i]$c, dat[i-(1:i)]$All) 
    y3 <- max(which(x3 %in% TRUE)) 
    dat[i, ThirdMatchingID := dat[i-y3]$e] 

} 

다음으로, 우리는 MatchingID 컬럼의 초기 일치하는 행을 찾아 자신의 열을 설정하는 pmin를 사용합니다. 이는 행 25에 일치 a이 있고 행 12에 b과 일치하는 경우입니다. 그것은 당신에게 12를 줄 것입니다 (나는 당신이 당신의 질문에 기초하여 원하는 것이라고 생각합니다).

dat$MinID <- pmin(dat$FirstMatchingID, dat$SecondMatchingID, dat$ThirdMatchingID, na.rm=T) 

마지막으로,이 루프는 e에서 모든 일치하는 ID 번호와 FinalID 열을 생성, 3 일을 할 것입니다 :

  1. MinIDNA (더 일치) e
  2. FinalID를 설정되어 있지 않은 경우 MinID이 숫자 인 경우 해당 행 (가장 빠른 시합)을 찾아 MinID이 숫자인지 확인하십시오. ; 그렇지 않은 경우 이전 일치 항목이없고 집합합니다. FinalID ~ MinID
  3. 위의 조건에 맞지 않는 행은 가장 나중에 일치하는 행이 i 인 특수한 경우입니다. 일치하는 항목을 찾아 FinalID으로 설정합니다. for (i in 1:nrow(dat)) { x <- dat[i]$MinID if (is.na(dat[i]$MinID)) { dat[i, FinalID := e] } else if (is.na(dat[x]$MinID)) { dat[i, FinalID := MinID] } else dat[i, FinalID := dat[x]$MinID] }

나는이 그것을해야한다고 생각; 어떻게 진행되는지 알려주세요. 나는 그 효율성이나 속도에 대해 아무런 주장을하지 않습니다.

+0

이것은 좋은 접근 방법 인 것 같습니다.나는 벡터화 된 솔루션을 찾고 있었는데, 이것이 더 빠를 것이라고 믿었지만, _The R Inferno_의 일부를 읽은 후에, 이것이 반드시 그런 것은 아니라는 것을 알게되었습니다. 나는 몇 가지 질문을한다. 1) 왜'max (grep (...)) '를 사용하는 대신에'grepl'을 사용하고 나서'max'를 사용하여 최대 인덱스를 얻었습니까? 2)'dat [i] $ MinID'라고 쓰면,'$ $ MinID [i]'라고 쓰시겠습니까? 그것들은 나를 위해 다르게 작동합니다. 나는 실제 데이터에 대한 아이디어를 적용하고 있기 때문에 정확한 코드를 시도하지 않았으므로 구문의 정확성을 말할 수는 없지만 아이디어는 견고합니다. – njc

+0

어디 보자. 1)'x <- grepl (...'은 일치/불일치를위한 T/F의 벡터를 반환하고,'which (x % in % TRUE)'는 T/F 요소의 위치가 참임을 의미한다. 일치가 있었다면)'max'는 data.table (또는 현재 행 i에서 가장 먼 곳)의 가장 가까운 부분을 찾습니다 .2) 나는 그런 식으로 쓰려고했습니다. 내 전체 코드를 시도해보십시오. 변경 한 시점이 아니라 현재 상태 그대로 작동하지만 사용자가 직접 확인할 수 있습니다. – moman822

+0

감사! 어떻게''grep''이 작동하는지,''grep''로 직접 인덱스를 얻는 대신에 T/F 벡터를 생성 한 후 인덱스를 가져 오는 특별한 이유가 있는지 궁금합니다. 나는 어느 쪽의 길도 좋다고 생각한다. – njc

1

아마추어 시도이다. 나는 그것이 당신이 원하는 것을 해낼 것이라고 생각합니다. 더 나은 예제를 제공하기 위해 data.frame (현재는 data.table)을 2 행으로 확장했습니다.

이 루프는 의 ID가 가장 빠른 일치 항목 인 dat$FirstMatchingID이라는 새 열을 만듭니다. 나는 첫 번째 열, dat$a과 일치시키기 위해이 작업을 수행했지만, bc으로 쉽게 확장 할 수 있다고 생각합니다.

결과는
library(data.table) 

dat <- data.table(a = c('cat', 'canine', 'feline', 'dog', 'feline','puppy'), 
        b = c('feline', 'puppy', 'meower', 'wolf', 'kitten', 'dog'), 
        c = c('kitten', 'barker', 'kitty', 'canine', 'cat','wolf'), 
        d = c('shorthair', 'collie', '', '','',''), 
        e = c(1, 5, 3, 8, 4, 6)) 

dat[, All := paste(a, b,c),] 

for(i in 2:nrow(dat)) { 
    print(dat[i]) 
    x <- grepl(dat[i]$a, dat[i-(1:i)]$All) 
    y <- max(which(x %in% TRUE)) 
    dat[i, FirstMatchingID := dat[i-y]$e] 
} 

:

 a  b  c   d e     All FirstMatchingID 
1: cat feline kitten shorthair 1 cat feline kitten    NA 
2: canine puppy barker collie 5 canine puppy barker    NA 
3: feline meower kitty   3 feline meower kitty    1 
4: dog wolf canine   8  dog wolf canine    NA 
5: feline kitten cat   4 feline kitten cat    1 
6: puppy dog wolf   6  puppy dog wolf    5 

당신은 당신이 원하는 결과를 얻기 위해 행을 결합 할 방법을 찾을 수있다, 그러나 희망이 도움이!

+0

이것은 매우 도움이되는 제안이며 이미이 문제를 해결하기 시작했습니다. 지금 나는 1) 거대한 데이터 세트와 루핑이 느리기 때문에 루프 교체, 2) 모든 인스턴스가 이름의 "네트워크"에서 첫 번째 라인을 가리킬 수있는 방법을 찾고있다. 예를 들어, 여섯 번째 행이'개 도파리 '라고 말하면됩니다. 그럼 행 6에 대한 FirstMatchingID는 4가 될 것입니다. 그러나 행 6이 행 2 _via 행 four_에 연결되기 때문에, FirstMatchingID가 2가 되길 원합니다. 이러한 문제를 해결할 수 있다면 이미 도움이 될 것입니다. 놀라운 곳으로. 감사! – njc

관련 문제