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

У меня есть кадр данных с людьми, которым присвоен текстовый идентификатор, который объединяет название места с личным идентификатором (см. данные ниже). В конечном итоге мне нужно преобразовать набор данных из «длинного» в «широкий» (например, с помощью «изменить форму»), чтобы каждый человек содержал только одну строку. Для этого мне нужно назначить переменную «время», которую reshape может использовать для идентификации изменяющихся во времени ковариат и т. д. У меня есть (вероятно, плохой) код, чтобы сделать это для отдельных лиц, которые повторяются до двух раз, но мне нужно быть в состоянии идентифицировать до 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
}

person SMM    schedule 06.10.2011    source источник


Ответы (4)


Непонятно, что вы пытаетесь сделать, но я думаю, вы говорите, что вам нужно создать индекс времени для каждой строки по каждому уникальному 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
....
person Chase    schedule 06.10.2011
comment
Это не работает для меня. Возможно, где-то опечатка? - person Aaron left Stack Overflow; 06.10.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
person Aaron left Stack Overflow    schedule 06.10.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, чтобы это работало.

person nzcoops    schedule 12.10.2011
comment
Без проблем. Не забудьте обновить свой предпочтительный ответ и, на ваше усмотрение, поставить галочку под ним, чтобы люди могли видеть, что было наиболее полезным. Это также помогает вашим рейтингам выбрать предпочтительный ответ. - person nzcoops; 13.10.2011

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

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
}
)

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

person SMM    schedule 26.10.2011