通过将值除以 data.table 中周边区域观测值的平均值来创建摘要 table
Creating summary table by dividing values by the average of the observations in the surrounding area in data.table
我的数据的最小样本是;
library(data.table)
set.seed(1)
tbl <- data.table(store = c('A','A','A','A','A','A','A','B','B','B','B','B','B','C','C','C','C'),
year = c(2017,2017,2017,2017,2018,2018,2018,2017,2017,2017,2017,2017,2017,2017,2017,2017,2018),
week = c(12,13,15,16,2,3,4,18,19,20,22,24,25,1,2,3,2),
insert = sample(0:1,size = 17,replace = T),
demand = sample(200:250,size = 17,replace=T))
我想创建一个以这种方式计算的摘要table;
要计算插入列为1的效果,我必须将插入列的需求值除以一年内最近几周的需求值的平均值,取值那个星期左右的插入列为零
比如我需要计算A店2017年第3周的数据,则必须是:
rate <- 209 / mean(c(206,245))
但如果这一年有多个插页,例如 2017 年的商店 B,它应该是费率的平均值(第 19 周和第 20 周):
rate <- mean(224 / mean(c(240,236)), 245 / mean(c(240,236)))
如果我找不到它周围的两个值,我必须用它除以我找到的唯一值来计算一个比率。例如 2017 年的商店 C:
rate <- 243 / 224
如果我在插入的行周围找不到值,我需要传递 1。
最终摘要 table 应该是这样的;
desired_tbl <- data.table(store = c('A','A','B','C','C'),
year = c(2017,2018,2017,2017,2018),
rate = c(0.927,0.97,0.941,1.08,1))
desired_tbl
store year rate
<chr> <dbl> <dbl>
1 A 2017 0.927
2 A 2018 0.97
3 B 2017 0.941
4 C 2017 1.08
5 C 2018 1
我可以通过编写 for 循环和大量条件来完成所有这些操作,但我正在寻找一种矢量化方法来完成。也欢迎 dplyr 解决方案。
提前致谢。
这是一种可能的方式
- 首先,确定 store-years,其中
insert=1
行是连续的,然后折叠它们(即取它们的平均值)。在您的示例中,只有一个这样的(2017-B,第 19/20 周)。获取这些折叠的行,并将它们绑定回 insert=0
行,重新排序为 store
、year
、week
tbl[, `:=`(demand=as.double(demand), insert_id=rleid(insert))]
tbl <- rbind(
tbl[insert==0],
tbl[insert==1][, lapply(.SD, mean, na.rm=T), by=.(store,year,insert_id)]
)[order(store,year,week)]
- 接下来,获取
insert=1
行前后的值,按行生成这些值的平均值(m
),估计demand
与[=19的比率=],并保留 insert=1
行。
tbl[, c("v1","v2"):=shift(demand,c(-1,1)), by=.(store, year)]
tbl[, m:=mean(c(v1,v2), na.rm=T), by=1:nrow(tbl)]
tbl[, rate:=demand/m][insert==1,.(rate=mean(fifelse(is.na(rate),1,rate))), by=.(store,year)]
输出:
store year rate
<char> <num> <num>
1: A 2017 0.9268293
2: A 2018 0.9727273
3: B 2017 0.9852941
4: C 2017 1.0848214
5: C 2018 1.0000000
它与你想要的输出不一样,因为我相信你计算错了 2017-B。
将具有 insert
值 1 的 demand
值替换为 NA 给出 d
然后按组向前和向后填充 d
取两个方向的平均值并分成 demand
给出 rate
。然后仅保留 insert
1 行,并使用 mean
对 store
/year
组进行聚合 rate
。如果任何 rate
不是有限使用 1.
library(dplyr)
library(zoo)
tbl %>%
mutate(d = ifelse(insert == 1, NA, demand)) %>%
group_by(store, year) %>%
mutate(rate = demand /
rowMeans(cbind(na.locf0(d), na.locf0(d, fromLast = TRUE)), na.rm = TRUE)) %>%
filter(insert == 1) %>%
summarize(rate = mean(rate, na.rm = TRUE), .groups = "drop") %>%
mutate(rate = ifelse(is.finite(rate), rate, 1))
给予:
# A tibble: 5 x 3
store year rate
<chr> <dbl> <dbl>
1 A 2017 0.927
2 A 2018 0.973
3 B 2017 0.985
4 C 2017 1.08
5 C 2018 1
我的数据的最小样本是;
library(data.table)
set.seed(1)
tbl <- data.table(store = c('A','A','A','A','A','A','A','B','B','B','B','B','B','C','C','C','C'),
year = c(2017,2017,2017,2017,2018,2018,2018,2017,2017,2017,2017,2017,2017,2017,2017,2017,2018),
week = c(12,13,15,16,2,3,4,18,19,20,22,24,25,1,2,3,2),
insert = sample(0:1,size = 17,replace = T),
demand = sample(200:250,size = 17,replace=T))
我想创建一个以这种方式计算的摘要table;
要计算插入列为1的效果,我必须将插入列的需求值除以一年内最近几周的需求值的平均值,取值那个星期左右的插入列为零
比如我需要计算A店2017年第3周的数据,则必须是:
rate <- 209 / mean(c(206,245))
但如果这一年有多个插页,例如 2017 年的商店 B,它应该是费率的平均值(第 19 周和第 20 周):
rate <- mean(224 / mean(c(240,236)), 245 / mean(c(240,236)))
如果我找不到它周围的两个值,我必须用它除以我找到的唯一值来计算一个比率。例如 2017 年的商店 C:
rate <- 243 / 224
如果我在插入的行周围找不到值,我需要传递 1。
最终摘要 table 应该是这样的;
desired_tbl <- data.table(store = c('A','A','B','C','C'),
year = c(2017,2018,2017,2017,2018),
rate = c(0.927,0.97,0.941,1.08,1))
desired_tbl
store year rate
<chr> <dbl> <dbl>
1 A 2017 0.927
2 A 2018 0.97
3 B 2017 0.941
4 C 2017 1.08
5 C 2018 1
我可以通过编写 for 循环和大量条件来完成所有这些操作,但我正在寻找一种矢量化方法来完成。也欢迎 dplyr 解决方案。
提前致谢。
这是一种可能的方式
- 首先,确定 store-years,其中
insert=1
行是连续的,然后折叠它们(即取它们的平均值)。在您的示例中,只有一个这样的(2017-B,第 19/20 周)。获取这些折叠的行,并将它们绑定回insert=0
行,重新排序为store
、year
、week
tbl[, `:=`(demand=as.double(demand), insert_id=rleid(insert))]
tbl <- rbind(
tbl[insert==0],
tbl[insert==1][, lapply(.SD, mean, na.rm=T), by=.(store,year,insert_id)]
)[order(store,year,week)]
- 接下来,获取
insert=1
行前后的值,按行生成这些值的平均值(m
),估计demand
与[=19的比率=],并保留insert=1
行。
tbl[, c("v1","v2"):=shift(demand,c(-1,1)), by=.(store, year)]
tbl[, m:=mean(c(v1,v2), na.rm=T), by=1:nrow(tbl)]
tbl[, rate:=demand/m][insert==1,.(rate=mean(fifelse(is.na(rate),1,rate))), by=.(store,year)]
输出:
store year rate
<char> <num> <num>
1: A 2017 0.9268293
2: A 2018 0.9727273
3: B 2017 0.9852941
4: C 2017 1.0848214
5: C 2018 1.0000000
它与你想要的输出不一样,因为我相信你计算错了 2017-B。
将具有 insert
值 1 的 demand
值替换为 NA 给出 d
然后按组向前和向后填充 d
取两个方向的平均值并分成 demand
给出 rate
。然后仅保留 insert
1 行,并使用 mean
对 store
/year
组进行聚合 rate
。如果任何 rate
不是有限使用 1.
library(dplyr)
library(zoo)
tbl %>%
mutate(d = ifelse(insert == 1, NA, demand)) %>%
group_by(store, year) %>%
mutate(rate = demand /
rowMeans(cbind(na.locf0(d), na.locf0(d, fromLast = TRUE)), na.rm = TRUE)) %>%
filter(insert == 1) %>%
summarize(rate = mean(rate, na.rm = TRUE), .groups = "drop") %>%
mutate(rate = ifelse(is.finite(rate), rate, 1))
给予:
# A tibble: 5 x 3
store year rate
<chr> <dbl> <dbl>
1 A 2017 0.927
2 A 2018 0.973
3 B 2017 0.985
4 C 2017 1.08
5 C 2018 1