我有一个包含4000个唯一ID和大约350k行的数据框。
我正在努力寻找解决方案来解决以下问题:
对于每个单个ID,创建一个sequantial ID来标记每个子组(从每个新ID重新启动),这将允许我通过仅保留每个子组的头部和尾部来折叠数据帧。单身ID。
这将允许我通过对每个ID中每个子组的每个头部和尾部元素的其他特征进行一些操作来继续我的项目。
以下是复制示例的代码:
ID <- rep(1, 11)
Time <- seq(1:11)
Type <- c(4, 4, 4, 4, 3, 3, 3, 3, 5, 5, 5)
df1 <- data.frame(ID, Time, Type)
ID <- rep(2, 9)
Time <- seq(1:9)
Type <- c(2, 2, 2, 3, 3, 3, 2, 2, 2)
df2 <- data.frame(ID, Time, Type)
ID <- rep(3, 5)
Time <- seq(1:5)
Type <- rep(4, 5)
df3 <- data.frame(ID, Time, Type)
ID <- rep(4, 10)
Time <- seq(1:10)
Type <- c(5, 5, 5, 2, 2, 2, 1, 1, 1, 1)
df4 <- data.frame(ID, Time, Type)
df <- rbind(df1, df2, df3, df4)
label <-c(1,1,1,1,2,2,2,2,3,3,3,1,1,1,2,2,2,3,3,3,1,1,1,1,1,1,1,1,2,2,2,3,3,3,3)
label_df<- cbind(df, label)
最终解决方案应如下所示,需要应用于4000个唯一ID,总共约350k行:
ID <- c(1,1,1,1,1,1,2,2,2,2,2,2,3,3,4,4,4,4,4,4)
Type <- c(4,4,3,3,5,5,2,2,3,3,2,2,4,4,5,5,2,2,1,1)
Time <- c(1,4,5,8,9,11,1,3,4,6,7,9,1,5,1,3,4,6,7,10)
Label <- c(1, 1, 2, 2, 3, 3,1, 1, 2, 2, 3, 3, 1, 1, 1, 1, 2, 2,3,3)
solution_df <- data.frame(ID, Type, Time, Label)
注意:我正在寻找的标签是一个序列号,可以增加每个类型的变化。这意味着,例如,ID == 2的结果必须是
ID2 <- c(2,2,2,2,2,2)
Time_ID2 <- c(1,3,4,6,7,9)
Type_ID2 <- c(2,2,3,3,2,2)
Label_ID2 <-c(1,1,2,2,3,3)
而不是
Label_ID2 <- c(1,1,2,2,1,1)
我希望问题很明确,我遵循规则。
答案 0 :(得分:0)
这是一种方法。
library(tidyverse)
df %>%
group_by(ID) %>%
mutate(label = as.integer(factor(Type, levels = unique(Type)))) %>%
基本上在按ID分组后,将Type转换为factor并返回到每个组中的整数。
但是,此方法会将Type的每个唯一值计为属于同一个子组。例如:5, 5, 5, 3, 3, 3, 5, 5, 5
标记为1, 1, 1, 2, 2, 2, 1, 1, 1
。如果您的意图是1, 1, 1, 2, 2, 2, 3, 3, 3
,最好使用rle
函数:
df %>%
group_by(ID) %>%
mutate(label = rep(1:length(rle(Type)$lengths), times = rle(Type)$lengths))
#part of output:
12 2 2 1
13 2 2 1
14 2 2 1
15 2 3 2
16 2 3 2
17 2 3 2
18 2 2 3
19 2 2 3
20 2 2 3
答案 1 :(得分:0)
使用tidyverse
:
如果要保留排序并且要保留每个 ID +类型块的第一次和最后一次观察,那么重复ID +类型组的独立性,可以使用{ {1}}和lag()
,它只是检查两个识别变量之一的数量是否有变化。
lead()
对于标签,missuse与df %>%
mutate(id = row_number(),
nr = nrow(.),
select1 = ifelse(Type!=lag(Type), 1, 0) +
ifelse(Type!=lead(Type), 1, 0) +
ifelse(ID!=lag(ID), 1, 0) +
ifelse(ID!=lead(ID), 1, 0),
select2 = ifelse(id==1, 1, 0) + ifelse(id==nr, 1, 0)) %>%
filter(select1>=1 | select2>=1) %>%
select(-id, -nr, -select1, -select2)
的解决方案似乎是最严格的解决方案,因此,如果您之前添加该部分,或者将所有内容整合到一个步骤中,您可以一步完成所有操作:
rle()
答案 2 :(得分:0)
OP已要求在每个Type
组中为每个连续的连续行数设置相同的值ID
。
这需要使用rleid()
函数来创建标签:
library(data.table)
result <- setDT(df)[
# create labels for grouping
, Label := rleid(Type), by = ID][
# pick first and last element of each group
, .SD[c(1L, .N)], by = .(ID, Label)]
all.equal(setcolorder(result, names(solution_df)), setDT(solution_df))
[1] TRUE
result
ID Type Time Label 1: 1 4 1 1 2: 1 4 4 1 3: 1 3 5 2 4: 1 3 8 2 5: 1 5 9 3 6: 1 5 11 3 7: 2 2 1 1 8: 2 2 3 1 9: 2 3 4 2 10: 2 3 6 2 11: 2 2 7 3 12: 2 2 9 3 13: 3 4 1 1 14: 3 4 5 1 15: 4 5 1 1 16: 4 5 3 1 17: 4 2 4 2 18: 4 2 6 2 19: 4 1 7 3 20: 4 1 10 3