Создайте порядковый номер (счетчик) для строк в каждой группе кадра данных
Как мы можем генерировать уникальные номера идентификаторов в каждой группе кадра данных? Вот некоторые данные, сгруппированные по "personid":
personid date measurement
1 x 23
1 x 32
2 y 21
3 x 23
3 z 23
3 y 23
Я хочу добавить столбец id с уникальным значением для каждой строки в каждом подмножестве, определяемом "personid", всегда начиная с 1
, Это мой желаемый результат:
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
Я ценю любую помощь.
6 ответов
Немного dplyr
альтернативы, используя удобные функции row_number
а также n
,
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))
Вы также можете использовать getanID
из пакета splitstackshape
, Обратите внимание, что входной набор данных возвращается как data.table
,
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
Обманчиво названный ave()
функция с аргументом FUN=seq_along
Достигнет это красиво - даже если ваш personid
колонка строго не упорядочена.
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
С помощью data.table
и при условии, что вы хотите заказать по date
в пределах personid
подмножество
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
Если вы хотите не хотите заказывать по 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
Любое из следующего также будет работать
DT[, id := seq_along(measurement), by = personid]
DT[, id := seq_along(date), by = personid]
Эквивалентные команды, использующие 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))
Я думаю, что есть законная команда для этого, но я не могу вспомнить это. Итак, вот один из способов:
> 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
Это работает, потому что duplicated
возвращает логический вектор cumsum
оценивает числовые векторы, поэтому логическое приведение к числовому.
Вы можете сохранить результат в свой data.frame как новый столбец, если хотите:
dat$id <- cumsum(duplicated(test))+1
Предполагая, что ваши данные находятся в data.frame с именем Data
, это сделает свое дело:
# 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))
Ты можешь использовать 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