英文:
R tidyverse create duplicate rows based on a fixed variable
问题
我有一个R数据框,其中包含每个id的start和end测量值。end - start的最小可能值是min_sz = 2(已知差异,但实际数据中可能并不发生)。我希望基于一个固定值创建“块”,并根据start和end重叠的块数为每个id创建重复的行。
如果我将min_sz = 2作为我的块大小,我的计算和结果将如下所示:
min_sz = 2
df = tibble(
id = c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"),
start = c(0, 0, 0, 4, 4, 8, 10, 10, 16, 32),
end = c(4, 6, 16, 10, 22, 18, 36, 56, 42, 84),
)
df %>%
mutate(dur = end - start) %>%
mutate(n_min_chunks = dur / min_sz) %>%
uncount(n_min_chunks) %>%
group_by(id) %>%
mutate(row = row_number()) %>%
mutate(
chunk_start = start + (min_sz * (row - 1)),
chunk_end = start + (min_sz * row),
)
| # | id | start | end | dur | row | chunk_start | chunk_end |
|---|---|---|---|---|---|---|---|
| 1 | a | 0 | 4 | 4 | 1 | 0 | 2 |
| 2 | a | 0 | 4 | 4 | 2 | 2 | 4 |
| 3 | b | 0 | 6 | 6 | 1 | 0 | 2 |
| 4 | b | 0 | 6 | 6 | 2 | 2 | 4 |
| 5 | b | 0 | 6 | 6 | 3 | 4 | 6 |
| 6 | c | 0 | 16 | 16 | 1 | 0 | 2 |
| 7 | c | 0 | 16 | 16 | 2 | 2 | 4 |
| 8 | c | 0 | 16 | 16 | 3 | 4 | 6 |
| .. | .. | ... | ... | ... | ... | ... | ... |
我希望执行类似的操作,但对于可能的任何req_sz,它是min_sz的倍数,并包括部分重叠。例如,如果我使用req_sz = 20,则我的输出应该如下所示(请注意,#5和#6具有部分重叠“4-20”和“20-22”):
| # | id | start | end | dur | chunk_start | chunk_end |
|---|---|---|---|---|---|---|
| 1 | a | 0 | 4 | 4 | 0 | 20 |
| 2 | b | 0 | 6 | 6 | 0 | 20 |
| 3 | c | 0 | 16 | 16 | 0 | 20 |
| 4 | c | 4 | 10 | 6 | 0 | 20 |
| 5 | c | 4 | 22 | 18 | 0 | 20 |
| 6 | c | 4 | 22 | 18 | 20 | 40 |
| .. | .. | ... | ... | ... | ... | ... |
但我一直无法找到一个允许我扩展这个“块分割”操作的数学解决方案。
任何帮助都将不胜感激!
英文:
I have an R dataframe that has start and end measurements for each id. The least possible value for end - start is min_sz = 2 (known difference, but may not actually occur in the data). I wish to create "chunks" based on a fixed value and create duplicate rows for each id, based on the number of chunks that start and end overlap.
If I were to use min_sz = 2 as my chunk size, my calculation and result would look something like this:
min_sz = 2
df = tibble(
id = c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"),
start = c(0, 0, 0, 4, 4, 8, 10, 10, 16, 32),
end = c(4, 6, 16, 10, 22, 18, 36, 56, 42, 84),
)
df %>%
mutate(dur = end - start) %>%
mutate(n_min_chunks = dur / min_sz) %>%
uncount(n_min_chunks) %>%
group_by(id) %>%
mutate(row = row_number()) %>%
mutate(
chunk_start = start + (min_sz * (row - 1)),
chunk_end = start + (min_sz * row),
)
| # | id | start | end | dur | row | chunk_start | chunk_end |
|---|---|---|---|---|---|---|---|
| 1 | a | 0 | 4 | 4 | 1 | 0 | 2 |
| 2 | a | 0 | 4 | 4 | 2 | 2 | 4 |
| 3 | b | 0 | 6 | 6 | 1 | 0 | 2 |
| 4 | b | 0 | 6 | 6 | 2 | 2 | 4 |
| 5 | b | 0 | 6 | 6 | 3 | 4 | 6 |
| 6 | c | 0 | 16 | 16 | 1 | 0 | 2 |
| 7 | c | 0 | 16 | 16 | 2 | 2 | 4 |
| 8 | c | 0 | 16 | 16 | 3 | 4 | 6 |
| .. | .. | ... | ... | ... | ... | ... | ... |
I wish to apply a similar operation, but for potentially any req_sz that's a multiple of min_sz and includes partial overlaps. If I were to use req_sz = 20 for example, my output should look something like this (note #5 & #6 with partial overlaps "4-20" & "20-22"):
| # | id | start | end | dur | chunk_start | chunk_end |
|---|---|---|---|---|---|---|
| 1 | a | 0 | 4 | 4 | 0 | 20 |
| 2 | b | 0 | 6 | 6 | 0 | 20 |
| 3 | c | 0 | 16 | 16 | 0 | 20 |
| 4 | c | 4 | 10 | 6 | 0 | 20 |
| 5 | c | 4 | 22 | 18 | 0 | 20 |
| 6 | c | 4 | 22 | 18 | 20 | 40 |
| .. | .. | ... | ... | ... | ... | ... |
but I've been unable to come up with a mathematical solution that allows me to scale this "chunking" operation.
Any help would be greatly appreciated!
答案1
得分: 1
在基本的R语言中,您可以编写以下函数来实现相同的功能:
explode <- function(data, by){
f <- function(...){
s <- list(...)[c('start', 'end')]
mat <- embed(seq((s$start %/% by) * by, (s$end %/% by + 1) * by, by), 2)
data.frame(...,dur = s$end - s$start, chk_st = mat[,2], chk_ed = mat[,1])
}
do.call(rbind, do.call(Map, c(f, data, by = by)))
}
explode(df, by=20)
id start end dur chunck_start chunk_end
a a 0 4 4 0 20
b b 0 6 6 0 20
c c 0 16 16 0 20
d d 4 10 6 0 20
e.1 e 4 22 18 0 20
e.2 e 4 22 18 20 40
f f 8 18 10 0 20
g.1 g 10 36 26 0 20
g.2 g 10 36 26 20 40
h.1 h 10 56 46 0 20
h.2 h 10 56 46 20 40
h.3 h 10 56 46 40 60
i.1 i 16 42 26 0 20
i.2 i 16 42 26 20 40
i.3 i 16 42 26 40 60
j.1 j 32 84 52 20 40
j.2 j 32 84 52 40 60
j.3 j 32 84 52 60 80
j.4 j 32 84 52 80 100
请注意,这是基于R语言的函数,用于实现您提供的功能,并对输入数据进行操作。
英文:
in base R you could write a function to accomplish the same:
explode <- function(data, by){
f <- function(...){
s <- list(...)[c('start', 'end')]
mat <- embed(seq((s$start %/% by) * by, (s$end %/% by + 1) * by, by), 2)
data.frame(...,dur = s$end - s$start, chk_st = mat[,2], chk_ed = mat[,1])
}
do.call(rbind, do.call(Map, c(f, data, by = by)))
}
explode(df, by=20)
id start end dur chunck_start chunk_end
a a 0 4 4 0 20
b b 0 6 6 0 20
c c 0 16 16 0 20
d d 4 10 6 0 20
e.1 e 4 22 18 0 20
e.2 e 4 22 18 20 40
f f 8 18 10 0 20
g.1 g 10 36 26 0 20
g.2 g 10 36 26 20 40
h.1 h 10 56 46 0 20
h.2 h 10 56 46 20 40
h.3 h 10 56 46 40 60
i.1 i 16 42 26 0 20
i.2 i 16 42 26 20 40
i.3 i 16 42 26 40 60
j.1 j 32 84 52 20 40
j.2 j 32 84 52 40 60
j.3 j 32 84 52 60 80
j.4 j 32 84 52 80 100
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论