2017-02-20 5 views
1

R에서 미리 지정한 횟수만큼 행을 반복하는 것에 대한 여러 가지 질문이 있지만 특정 질문을 처리 할 수는 없습니다. 묻고있어.데이터 프레임의 다른 값을 기준으로 데이터 프레임의 행 블록을 반복하십시오.

각 응답자가 5 ~ 10 개 질문에 답변하는 설문의 응답 데이터 프레임이 있습니다. 장난감 예를 들어 :

df <- data.frame(ID = rep(1:2, each = 5), 
      Response = sample(LETTERS[1:4], 10, replace = TRUE), 
      Weight = rep(c(2,3), each = 5)) 

> df 
    ID Response Weight 
1 1  D  2 
2 1  C  2 
3 1  D  2 
4 1  D  2 
5 1  B  2 
6 2  D  3 
7 2  C  3 
8 2  B  3 
9 2  D  3 
10 2  B  3 

나는 블록으로 블록 다음 응답자 2의 응답으로, 두 번 세 번, 을 응답자 1의 답변을 반복하고 싶은, 나는 응답의 각 블록을 원하는 고유 한 ID가 있어야합니다. 즉,이처럼 보이게 최종 결과를 원하는 :

 ID Response Weight 
1 11  D  2 
2 11  C  2 
3 11  D  2 
4 11  D  2 
5 11  B  2 
6 12  D  2 
7 12  C  2 
8 12  D  2 
9 12  D  2 
10 12  B  2 
11 21  D  3 
12 21  C  3 
13 21  B  3 
14 21  D  3 
15 21  B  3 
16 22  D  3 
17 22  C  3 
18 22  B  3 
19 22  D  3 
20 22  B  3 
21 23  D  3 
22 23  C  3 
23 23  B  3 
24 23  D  3 
25 23  B  3 

내가 뭘하는 방법을이 내 데이터 집합> 3000 명 응답자가 주어진, 정말 현재 어설픈이며, 참을 수있다 느린. 이 작업을 수행하는 빠른 방법은

df.expanded <- NULL 
for(i in unique(df$ID)) { 
    x <- df[df$ID == i,] 
    y <- x[rep(seq_len(nrow(x)), x$Weight),1:3] 
    y$order <- rep(1:max(x$Weight), nrow(x)) 
    y <- y[with(y, order(order)),] 
    y$IDNew <- rep(max(y$ID)*100 + 1:max(x$Weight), each = nrow(x)) 
    df.expanded <- rbind(df.expanded, y) 
} 

있습니까 :

여기 내 코드입니까?

+1

왜 그런 작업을 수행하겠습니까? – DJJ

+0

예. 저는 응답의 잠복 (latent-class) 조건부 로짓 분석을하고 있습니다 (실제 데이터 집합에서 위의 문자가 아닌 1/0입니다). 실제로 분석을하고있는 Stata에서 lclogit은 가중치를 받아들이지 않으므로 역 확률 가중치를 사용합니다. – TheChainsOfMarkov

+1

'ID 1 '을 두 번 반복하십시오 :'df [df $ ID == 1] [rep (seq_len (nf) (df $ ID == 1)]), –

답변

1

더 쉬운 해결책이 있습니다. 코드에 표시된대로 Weight을 기반으로 행을 복제하려고한다고 가정합니다.

df2 <- df[rep(seq_along(df$Weight), df$Weight), ] 
df2$ID <- paste(df2$ID, unlist(lapply(df$Weight, seq_len)), sep = '') 

# sort the rows 
df2 <- df2[order(df2$ID), ] 

이 방법이 더 빠릅니까? 보기 :

library(microbenchmark) 

microbenchmark(
    m1 = { 
     df.expanded <- NULL 
     for(i in unique(df$ID)) { 
      x <- df[df$ID == i,] 
      y <- x[rep(seq_len(nrow(x)), x$Weight),1:3] 
      y$order <- rep(1:max(x$Weight), nrow(x)) 
      y <- y[with(y, order(order)),] 
      y$IDNew <- rep(max(y$ID)*100 + 1:max(x$Weight), each = nrow(x)) 
      df.expanded <- rbind(df.expanded, y) 
     } 
    }, 
    m2 = { 
     df2 <- df[rep(seq_along(df$Weight), df$Weight), ] 
     df2$ID <- paste(df2$ID, unlist(lapply(df$Weight, seq_len)), sep = '') 

     # sort the rows 
     df2 <- df2[order(df2$ID), ] 
    } 
) 

# Unit: microseconds 
# expr  min  lq  mean median  uq  max neval 
# m1 806.295 862.460 1101.6672 921.0690 1283.387 2588.730 100 
# m2 171.731 194.199 245.7246 214.3725 283.145 506.184 100 

다른 더 효율적인 방법이있을 수 있습니다.

+0

와우. 이것은 훨씬 빨랐습니다. 고맙습니다! – TheChainsOfMarkov

1

또 다른 접근법은 data.table을 사용하는 것입니다.

당신이 당신의 data.table으로 "DT"로 시작하고 가정, 시도 :

library(data.table) 
DT[, list(.id = rep(seq(Weight[1]), each = .N), Weight, Response), .(ID)] 

나는 함께 ID 열을 붙여, 대신, 두 번째 열을 만들지 않았습니다. 그건 좀 더 융통성있게 보입니다.


테스트 용 데이터. n을 변경하여 재생할 더 큰 데이터 세트를 만듭니다.

set.seed(1) 
n <- 5 
weights <- sample(3:15, n, TRUE) 
df <- data.frame(ID = rep(seq_along(weights), weights), 
       Response = sample(LETTERS[1:5], sum(weights), TRUE), 
       Weight = rep(weights, weights)) 
DT <- as.data.table(df) 
관련 문제