2012-08-16 4 views
26

Wie können wir in jeder Gruppe eines Datenrahmens eindeutige ID-Nummern generieren? Hier einige Daten gruppiert nach „PersonID“:Erstellen Sie eine laufende Nummer (Zähler) für die Zeilen in jeder Gruppe eines Datenrahmens

personid date measurement 
1   x  23 
1   x  32 
2   y  21 
3   x  23 
3   z  23 
3   y  23 

Ich möchte für jede Zeile eine ID-Spalte mit einem eindeutigen Wert hinzugefügt, die in jeder Teilmenge definiert durch „PersonID“, immer mit 1 beginnen. Dies ist meine gewünschte Ausgabe:

personid date measurement id 
1   x  23   1 
1   x  32   2 
2   y  21   1 
3   x  23   1 
3   z  23   2 
3   y  23   3 

Ich schätze jede Hilfe.

Antwort

7

Ich denke, es gibt einen Dosen-Befehl für diese, aber ich kann mich nicht daran erinnern. Also hier ist ein Weg:

> test <- sample(letters[1:3],10,replace=TRUE) 
> cumsum(duplicated(test)) 
[1] 0 0 1 1 2 3 4 5 6 7 
> cumsum(duplicated(test))+1 
[1] 1 1 2 2 3 4 5 6 7 8 

Dies funktioniert, weil duplicated eine logische Vektor zurückgibt. cumsum wertet numerische Vektoren aus, so wird das Logische auf Numerisch gesetzt.

Sie das Ergebnis Ihrer data.frame als neue Spalte speichern können, wenn Sie wollen:

dat$id <- cumsum(duplicated(test))+1 
5

Angenommen, Ihre Daten sind in einem data.frame Data genannt, wird dies den Trick:

# ensure Data is in the correct order 
Data <- Data[order(Data$personid),] 
# tabulate() calculates the number of each personid 
# sequence() creates a n-length vector for each element in the input, 
# and concatenates the result 
Data$id <- sequence(tabulate(Data$personid)) 
23

Die irreführende ave() Funktion, mit Argument FUN=seq_along, wird dies gut erreichen - auch wenn Ihre personid Spalte nicht streng geordnet ist.

df <- read.table(text = "personid date measurement 
1   x  23 
1   x  32 
2   y  21 
3   x  23 
3   z  23 
3   y  23", header=TRUE) 

## First with your data.frame 
ave(df$personid, df$personid, FUN=seq_along) 
# [1] 1 2 1 1 2 3 

## Then with another, in which personid is *not* in order 
df2 <- df[c(2:6, 1),] 
ave(df2$personid, df2$personid, FUN=seq_along) 
# [1] 1 1 1 2 3 2 
10

Mit data.table, und vorausgesetzt, Sie möchten mehr von date innerhalb der personid Teilmenge bestellen

library(data.table) 
DT <- data.table(Data) 

DT[,id := order(date), by = personid] 

## personid date measurement id 
## 1:  1 x   23 1 
## 2:  1 x   32 2 
## 3:  2 y   21 1 
## 4:  3 x   23 1 
## 5:  3 z   23 3 
## 6:  3 y   23 2 

Wenn Sie wünschen, durch date

DT[, id := 1:.N, by = personid] 

## personid date measurement id 
## 1:  1 x   23 1 
## 2:  1 x   32 2 
## 3:  2 y   21 1 
## 4:  3 x   23 1 
## 5:  3 z   23 2 
## 6:  3 y   23 3 

Jede der folgenden Bestellung nicht wünschen würde auch

DT[, id := seq_along(measurement), by = personid] 
DT[, id := seq_along(date), by = personid] 

Die entsprechenden Befehle plyr

library(plyr) 
# ordering by date 
ddply(Data, .(personid), mutate, id = order(date)) 
# in original order 
ddply(Data, .(personid), mutate, id = seq_along(date)) 
ddply(Data, .(personid), mutate, id = seq_along(measurement)) 
2

Sie können sqldf

df<-read.table(header=T,text="personid date measurement 
1   x  23 
1   x  32 
2   y  21 
3   x  23 
3   z  23 
3   y  23") 

library(sqldf) 
sqldf("SELECT a.*, COUNT(*) count 
     FROM df a, df b 
     WHERE a.personid = b.personid AND b.ROWID <= a.ROWID 
     GROUP BY a.ROWID" 
) 

# personid date measurement count 
#1  1 x   23  1 
#2  1 x   32  2 
#3  2 y   21  1 
#4  3 x   23  1 
#5  3 z   23  2 
#6  3 y   23  3 
15

Einige dplyr Alternativen, mit Komfortfunktionen row_number und n verwenden verwenden.

library(dplyr) 
df %>% group_by(personid) %>% mutate(id = row_number()) 
df %>% group_by(personid) %>% mutate(id = 1:n()) 
df %>% group_by(personid) %>% mutate(id = seq_len(n())) 
df %>% group_by(personid) %>% mutate(id = seq_along(personid)) 

Sie auch getanID von Paket splitstackshape verwenden. Beachten Sie, dass das Eingabe-Dataset als data.table zurückgegeben wird.

getanID(data = df, id.vars = "personid") 
# personid date measurement .id 
# 1:  1 x   23 1 
# 2:  1 x   32 2 
# 3:  2 y   21 1 
# 4:  3 x   23 1 
# 5:  3 z   23 2 
# 6:  3 y   23 3 
Verwandte Themen