我正在努力寻找一项需要运行超过一千万条记录的非常简单的任务的解决方案。
假设以下数据集:
mydf <- structure(list(group_ID = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4,
4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
9), element_index= c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L,
12L, 13L, 14L, 15L, 16L, 17L, 18L, 1L, 2L, 3L, 4L, 5L, 6L, 7L,
8L, 9L, 1L, 2L, 3L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 1L, 2L, 3L, 4L,
5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 1L, 2L, 3L, 4L, 5L, 6L,
7L, 8L, 9L, 10L, 11L, 12L, 1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L,
5L, 6L, 7L, 8L), value= c(8045762L, 259L, 155L, 167L,
110L, 175L, 135L, 0L, 0L, 0L, 0L, 150L, 0L, 0L, 115L, 0L, 0L,
396L, 11175L, 0L, 0L, 0L, 261L, 0L, 170L, 0L, 576L, 5807L, 0L,
280L, 48663L, 0L, 0L, 497L, 7298L, 0L, 441L, 160725L, 0L, 0L,
0L, 0L, 335L, 0L, 0L, 0L, 0L, 0L, 0L, 356L, 35462L, 0L, 0L, 0L,
0L, 0L, 0L, 0L, 265L, 0L, 0L, 360L, 780L, 0L, 0L, 0L, 371L, 48394L,
0L, 0L, 0L, 341L, 0L, 0L, 386L)), .Names = c("group_ID", "element_index",
"value"), class = "data.frame", row.names = c(NA, 75L))
基本上,主要概念是:
1.每个group_ID的第一个元素元素始终到subgroup_ID == 1
,
2.在value == 0
增加subgroup_ID
时,不得考虑subgroup_id
的元素
3. 1
value != 0
从<{>} 元素1
开始,value != 0
每增加一个value != 0
value == 0
(从value != 0
的第二个元素的1开始;)
4. subgroup_ID = c(1,1,2,3,4,5,6,7,7,7,7,7,8,8,8,9,9,9,1,1,1,1,1,2,2,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2)
solution_df <- data.frame(mydf, subgroup_ID)
元素与subgroup_ID
的第一个下一个元素相关联。 观察图片,这意味着元素2和3被分配给元素4的subgroup_ID。
解决方案如下:
subgroup_ID
此问题的目的是让group_ID
将每个组划分为细分,而创建1
的规则如下:
- 每个subgroup_ID
的第一个元素始终为1
- 每次有value != 0
sendInfo()
增加sendInfo()
我希望问题很明确,请不要犹豫要求澄清。
答案 0 :(得分:2)
这里我们假设任何组的规则是用0替换值的第二个非零元素,然后通过从1开始形成结果,并在每次遇到后续非零时递增1。 / p>
由于每个组中第一个值元素根据注释总是非零,我们可以通过暂时将第一个元素替换为零来找到第二个非零,然后在剩下的内容中搜索第一个非零值
没有使用任何包裹。
Seq <- function(x) {
x[head(which(replace(x, 1, 0) != 0), 1)] <- 0
cumsum(x != 0)
}
transform(mydf, subid = ave(value, group_ID, FUN = Seq))
给出与问题中显示的答案相同的答案:
group_ID element_index value subid
1 1 1 123 1
2 1 2 0 1
3 1 3 0 1
4 1 4 456 1
5 1 5 214 2
6 2 1 20 1
7 2 2 0 1
8 2 3 30 1
9 3 1 10 1
10 3 2 0 1
11 3 3 10 1
12 3 4 20 2
答案 1 :(得分:2)
您还可以尝试numpy
解决方案
tidyverse
答案 2 :(得分:1)
group_ID <- c(1,1,1,1,1,2,2,2,3,3,3,3)
element_index <- c(1, 2, 3, 4, 5, 1, 2, 3, 1, 2, 3, 4) #the element are ordered within each group_ID
value <- c(123, 0, 0, 456, 214, 20, 0, 30, 10, 0, 10, 20)
mydf <- data.frame(group_ID, element_index, value)
library(dplyr)
mydf %>%
group_by(group_ID) %>%
mutate(v_upd = cumsum(ifelse(value * lag(value, default = 0) != 0, 1, 0)) + 1) %>%
ungroup()
# # A tibble: 12 x 4
# group_ID element_index value v_upd
# <dbl> <dbl> <dbl> <dbl>
# 1 1 1 123 1
# 2 1 2 0 1
# 3 1 3 0 1
# 4 1 4 456 1
# 5 1 5 214 2
# 6 2 1 20 1
# 7 2 2 0 1
# 8 2 3 30 1
# 9 3 1 10 1
# 10 3 2 0 1
# 11 3 3 10 1
# 12 3 4 20 2
为了更好地理解这个过程,请检查这个(类似的)将每个步骤存储为变量的过程:
mydf %>%
group_by(group_ID) %>% # for each group ID
mutate(lag1_value = lag(value, default = 0)) %>% # get the previous value of "value"
mutate(v = ifelse(value * lag1_value != 0, 1, 0), # for both current and previous value is different than 0 flag as 1
v_upd = cumsum(v)+1) %>% # get cummulative sum of flags and add 1
ungroup() # forget the grouping
# # A tibble: 12 x 6
# group_ID element_index value lag1_value v v_upd
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 1 1 123 0 0 1
# 2 1 2 0 123 0 1
# 3 1 3 0 0 0 1
# 4 1 4 456 0 0 1
# 5 1 5 214 456 1 2
# 6 2 1 20 0 0 1
# 7 2 2 0 20 0 1
# 8 2 3 30 0 0 1
# 9 3 1 10 0 0 1
# 10 3 2 0 10 0 1
# 11 3 3 10 0 0 1
# 12 3 4 20 10 1 2