提前致谢.我有以下数据:
df <- data.frame(person=c(1,1,1,1,2,2,2,2,3,3,3,3),
neighborhood=c("A","A","A","A","B","B","C","C","D","D","E","F"))
Run Code Online (Sandbox Code Playgroud)
我想生成一个新列,它给出了每个人在面板进行过程中所经过的邻域的累积计数.像这样:
df2 <- data.frame(person=c(1,1,1,1,2,2,2,2,3,3,3,3),
neighborhood=c("A","A","A","A","B","B","C","C","D","D","E","F"),
moved=c(0,0,0,0,0,0,1,1,0,0,1,2)
)
Run Code Online (Sandbox Code Playgroud)
再次感谢.
我们可以按'人'使用组,然后通过match'邻域' 创建'移动' 及其unique值以获得索引并减去1.
df %>%
group_by(person) %>%
mutate(moved = match(neighborhood, unique(neighborhood))-1)
# person neighborhood moved
# <dbl> <fctr> <dbl>
#1 1 A 0
#2 1 A 0
#3 1 A 0
#4 1 A 0
#5 2 B 0
#6 2 B 0
#7 2 C 1
#8 2 C 1
#9 3 D 0
#10 3 D 0
#11 3 E 1
#12 3 F 2
Run Code Online (Sandbox Code Playgroud)
或者使用factor与levels指定为unique在"街区"值,强制为"整数"和减去1.
df %>%
group_by(person) %>%
mutate(moved = as.integer(factor(neighborhood, levels = unique(neighborhood)))-1)
# person neighborhood moved
# <dbl> <fctr> <dbl>
#1 1 A 0
#2 1 A 0
#3 1 A 0
#4 1 A 0
#5 2 B 0
#6 2 B 0
#7 2 C 1
#8 2 C 1
#9 3 D 0
#10 3 D 0
#11 3 E 1
#12 3 F 2
Run Code Online (Sandbox Code Playgroud)
这也可以通过包中rleid的frank功能或功能轻松实现data.table:
library(data.table)
# with 'rleid'
setDT(df)[, moved := rleid(neighborhood)-1, by = person]
# with 'frank'
setDT(df)[, moved := frank(neighborhood, ties.method='dense')-1, by = person]
Run Code Online (Sandbox Code Playgroud)
结果:
> df
person neighborhood moved
1: 1 A 0
2: 1 A 0
3: 1 A 0
4: 1 A 0
5: 2 B 0
6: 2 B 0
7: 2 C 1
8: 2 C 1
9: 3 D 0
10: 3 D 0
11: 3 E 1
12: 3 F 2
Run Code Online (Sandbox Code Playgroud)
有了dplyr可以使用的dense_rank功能:
library(dplyr)
df %>%
group_by(person) %>%
mutate(moved = dense_rank(neighborhood)-1)
Run Code Online (Sandbox Code Playgroud)