Как назначить количество повторов для кадра данных на основе элементов идентифицирующего вектора в R? - PullRequest
1 голос
/ 06 октября 2011

У меня есть фрейм данных с лицами, которым назначен текстовый идентификатор, который объединяет название места с личным идентификатором (см. Данные ниже). В конечном счете мне нужно выполнить преобразование набора данных из «длинного» в «широкий» (например, с использованием «изменения формы»), чтобы каждый отдельный пользователь содержал только одну строку. Чтобы сделать это, мне нужно назначить переменную «время», которую можно использовать для изменения формы, чтобы идентифицировать изменяющиеся во времени ковариаты и т.д. быть в состоянии идентифицировать до 18 повторных случаев. Код ниже работает нормально, если я удаляю строку, которой предшествует хеш, но идентифицирует только до двух повторов. Если я оставлю эту строку в (что может показаться необходимым для людей, повторенных более двух раз), R захлебнется, выдав следующую ошибку (предположительно потому, что первый человек повторяется только дважды):

Error in if (data$uid[i] == data$uid[i - 2]) { : 
  argument is of length zero

Может кто-нибудь помочь с этим? Заранее спасибо!

place <- rep("ny",10)
pid <- c(1,1,2,2,2,3,4,4,5,5)
uid<- paste(place,pid,sep="")
time <- rep(0,10)
data <- cbind(uid,time)
data <- as.data.frame(data)
data$time <- as.numeric(data$time)

#bad code
data$time[1] <- 1 #need to set first so that loop doesn't go to a row that doesn't exist     (i.e., row 0)
for (i in 2:NROW(data)){
    data$time[i] <- 1 #set first occurrence to 1
    if (data$uid[i] == data$uid[i-1]) {data$time[i] <- 2} #set second occurrence to 2, etc.
    #if (data$uid[i] == data$uid[i-2]) {data$time[i] <- 3}
    i <- i+1
}

Ответы [ 4 ]

2 голосов
/ 06 октября 2011

Неясно, что вы пытаетесь сделать, но я думаю, что вы говорите, что вам нужно создать индекс времени для каждой строки на каждый уникальный uid. Это верно?

Если это так, дайте вихрь

library(plyr)
ddply(data, "uid", transform, time = seq_along(uid))

даст вам что-то вроде:

   uid time
1  ny1    1
2  ny1    2
3  ny2    1
4  ny2    2
5  ny2    3
....
1 голос
/ 06 октября 2011

Это то, что вы имеете в виду?

> d <- data.frame(uid = paste("ny",c(1,2,1,2,2,3,4,4,5,5),sep=""))
> out <- do.call(rbind, lapply(split(d, d$uid), function(x) {x$time <- 1:nrow(x); x}))
> rownames(out) <- NULL
> out
   uid time
1  ny1    1
2  ny1    2
3  ny2    1
4  ny2    2
5  ny2    3
6  ny3    1
7  ny4    1
8  ny4    2
9  ny5    1
10 ny5    2
0 голосов
/ 26 октября 2011

Попробовав вышеуказанные решения для больших наборов данных, я решил написать для этого свой собственный цикл. Это было очень много времени и все еще требовало разбивки данных на 50-элементные векторы, но в итоге это сработало:

system.time( for(i in 2:length(data$uid)) {
if(data$uid[i]==data$uid[i-1]) data$repeats[i] <- data$repeats[i-1]+1
  if ((i %% 1000)== 0) { #helps to keep track of how far the loop has gotten
    print(i) }
    i+1
}
)

Спасибо всем за помощь.

0 голосов
/ 12 октября 2011

Использование настроек фрейма данных:

place <- rep("ny",10)
pid <- c(1,1,2,2,2,3,4,4,5,5)
uid<- paste(place,pid,sep="")
time <- rep(0,10)
data <- cbind(uid,time)
data <- as.data.frame(data)

Вы можете использовать:

data$time <- sequence(table(data$uid))
data

Чтобы получить:

> data
   uid time
1  ny1    1
2  ny1    2
3  ny2    1
4  ny2    2
5  ny2    3
6  ny3    1
7  ny4    1
8  ny4    2
9  ny5    1
10 ny5    2

ПРИМЕЧАНИЕ: ваш data.frame ДОЛЖЕНчтобы это сработало, нужно сначала отсортировать его по uid.

...