假设以下列表:
df1 <- data.frame(id = 1:3,
x = 1:3,
y = 4:6,
level = rep("L1", 3))
df2 <- data.frame(id = 4:6,
x = 2:4,
y = 5:7,
level = rep("L1", 3))
df3 <- data.frame(id = 1:6,
x = 1:6,
y = 7:13,
level = rep("L2", 6))
my_list <- list(df1, df2, df3)
我现在想首先";循环;通过具有级别CCD_ 1的数据帧,并且在此示例中简单地取x+y的和(按行(。
然而,当我到达df3(其具有level=L2
(时,我希望首先行绑定来自df1和df2的各个求和结果,将该结果与df3匹配(基于id列(,然后对于df3/level=L2
,取x+y+来自L1级的结果的和。
如果只有两个级别,我可以硬编码,但是,我可能有很多级别。
所以我的问题是:我该如何编写函数或获取lapply/purrr::映射到代码的某个块,以便它为L1做一些事情,然后将这些结果输入到L2的下一个块中,一旦我们通过L2,我们就会进入L3,依此类推
运行类似lapply(my_list, custom_function)
的东西后的预期结果将是
result1 <- data.frame(id = 1:3,
x = 1:3,
y = 4:6,
level = rep("L1", 3),
result = c(5, 7, 9))
result2 <- data.frame(id = 4:6,
x = 2:4,
y = 5:7,
level = rep("L1", 3),
result = c(7, 9, 11))
result3 <- data.frame(id = 1:6,
x = 1:6,
y = 7:12,
level = rep("L2", 6),
result_L1 = c(5, 7, 9, 7, 9, 11),
result = c(13, 17, 21, 21, 25, 29))
final_result <- list(result1, result2, result3)
(稍微解释一下计算:
- df1,第一行:x+y是1+4,所以结果=5
- 当我们得到具有L2级的df3时,我们首先将这个结果(5(与df3匹配,然后取x+y+result_L1=1+7+5=13的和
复杂的操作发生在级别之间,所以我首先要重新组织一种结构,其中每个级别有一个数据帧的列表。自x + y
需要始终进行计算,我们也可以这样做:
library(tidyverse)
lvls <- bind_rows(my_list) %>%
mutate(result = x + y) %>%
split(.$level)
lvls
#> $L1
#> id x y level result
#> 1 1 1 4 L1 5
#> 2 2 2 5 L1 7
#> 3 3 3 6 L1 9
#> 4 4 2 5 L1 7
#> 5 5 3 6 L1 9
#> 6 6 4 7 L1 11
#>
#> $L2
#> id x y level result
#> 7 1 1 7 L2 8
#> 8 2 2 8 L2 10
#> 9 3 3 9 L2 12
#> 10 4 4 10 L2 14
#> 11 5 5 11 L2 16
#> 12 6 6 12 L2 18
要添加上一级别的结果,我们可以使用accumulate()
:
lvls %>%
accumulate(function(l1, l2) {
l1 %>%
select(id, result0 = result) %>%
right_join(l2, by = "id") %>%
mutate(result = result + result0)
})
#> $L1
#> id x y level result
#> 1 1 1 4 L1 5
#> 2 2 2 5 L1 7
#> 3 3 3 6 L1 9
#> 4 4 2 5 L1 7
#> 5 5 3 6 L1 9
#> 6 6 4 7 L1 11
#>
#> $L2
#> id result0 x y level result
#> 1 1 5 1 7 L2 13
#> 2 2 7 2 8 L2 17
#> 3 3 9 3 9 L2 21
#> 4 4 7 4 10 L2 21
#> 5 5 9 5 11 L2 25
#> 6 6 11 6 12 L2 29
根据您评论中的额外上下文,我想不同的方法。这个想法仍然是跨级别累积权重,但我会将另一个逻辑推入一个助手函数来处理每个级别:
find_weights <- function(data, balance, stratify = character(), weights = "wt") {
if (length(stratify) > 0) {
# Apply separately to strata
strata <- data[stratify]
data <- split(data, strata) |>
lapply(find_weights, balance, weights = weights) |>
unsplit(strata)
return(data)
}
# Get initial weights
w0 <- data[[weights]]
if (is.null(w0)) {
w0 <- rep_len(1, nrow(data))
}
# Find balancing weights (use your function)
f <- factor(data[[balance]])
n <- as.numeric(tapply(w0, f, sum))
w <- prop.table(1 / n[f]) * sum(w0)
# Update weights
data[[weights]] <- w0 * w
data
}
一些示例数据:
data <- data.frame(country = rep(c("A", "B"), c(3, 5)), sex = c("m", "f"))
data
#> country sex
#> 1 A m
#> 2 A f
#> 3 A m
#> 4 B f
#> 5 B m
#> 6 B f
#> 7 B m
#> 8 B f
和级别描述:
opts <- list(
l1 = list(balance = "sex", stratify = "country"),
l2 = list(balance = "country")
)
然后应用,累积权重:
Reduce(function(data, opts) {
find_weights(data, opts$balance, opts$stratify)
}, opts, data, accumulate = TRUE)
#> [[1]]
#> country sex
#> 1 A m
#> 2 A f
#> 3 A m
#> 4 B f
#> 5 B m
#> 6 B f
#> 7 B m
#> 8 B f
#>
#> [[2]]
#> country sex wt
#> 1 A m 0.7500000
#> 2 A f 1.5000000
#> 3 A m 0.7500000
#> 4 B f 0.8333333
#> 5 B m 1.2500000
#> 6 B f 0.8333333
#> 7 B m 1.2500000
#> 8 B f 0.8333333
#>
#> [[3]]
#> country sex wt
#> 1 A m 1.0000000
#> 2 A f 2.0000000
#> 3 A m 1.0000000
#> 4 B f 0.6666667
#> 5 B m 1.0000000
#> 6 B f 0.6666667
#> 7 B m 1.0000000
#> 8 B f 0.6666667