根据 R 中的列表长度动态创建嵌套的 FOR 循环
Dynamically creating nested FOR loops based on the list length in R
假设我有一个这样的数据集dt
:
meta_cat
cat
sku
price
sales
bakery
bread
796590
22.6
24
bakery
bread
796595
19.8
20
bakery
doughnut
796588
30.6
36
bakery
sandwich
796640
45.9
42
bakery
sandwich
796643
43.3
45
fruits
feijoa
645342
97.2
5
fruits
orange
645675
35.7
78
fruits
orange
645677
43.9
65
fruits
feijoa
645342
92.9
11
此外,我有一个如下所示的列表,例如:
lvl_list <- list(c("meta_cat"),
c("cat"))
我事先不知道列表中会有多少层(列表长度可以是0(空列表),也可以是一、二、三等(在我们的例子中,有两个水平))。列表值对应于数据集中的列名称。
我的任务是运行基于列表长度的嵌套for循环。
如果列表为空,则不开始循环并执行main code
。
如果list length = 1,应该有1个这样的for循环:
for(i in unique(dt[[lvl_list[[1]]]])){
dt <- dt[get(lvl_list[[1]]) == I,] # make subset
# run main code
# .
# .
# main code
}
}
因此,在第一次迭代中,我们通过 meta_cat
列的第一个唯一值过滤 dt
(例如,仅选择 meta_cat = "bakery"
的记录)和 运行 main code
在此 dt
.
如果列表的长度 = 2,我们应该得到 2 个 for 循环:
for(i in unique(dt[[lvl_list[[1]]]])){
dt <- dt[get(lvl_list[[1]]) == i, ] # filter dt
for(j in unique(dt[[lvl_list[[2]]]])){
dt <- dt[get(lvl_list[[2]]) == j, ] # filter dt again
# run main code
# .
# .
# main code
}
}
所以,这里我们按两列的值过滤 dt
。
变量meta_cat
有2个唯一值,cat
变量有5个唯一值
代码执行的逻辑应该如下:在第一次迭代中,我们通过 meta_cat
的第一个值过滤 dt
(留在 dt
观察中,其中 meta_cat = "bakery"
) ,在第二个循环的第一次迭代中,我们通过 cat
变量的第一个值过滤 dt
(我们将选择 cat = "bread"
的观察值)。因此,我们得到 dt
,其中 meta_cat = "bakery"
和 cat = "bread"
。此外,此过滤后的 dt
用作建模代码的输入。
在第二次迭代中,原始 dt
被 meta_cat = "bakery"
和 cat = "doughnut"
过滤。然后主要代码执行到这个dt
,结束等等
如果列表中有 3 个级别,我们应该有 3 个 for 循环,等等
我的问题:是否可以根据列表长度动态创建嵌套 for 循环?
对于如何实施它的任何帮助,我将不胜感激。
使用 split
可能更容易
lst1 <- lapply(split(dt, dt[[lvl_list[[1]]]]), function(x)
split(x, x[[lvl_list[[2]]]]))
此外,由于这是一个递归拆分,使用 collapse
中的 rsplit
,默认情况下会进行递归拆分和 returns 嵌套列表`
library(collapse)
lst2 <- rsplit(dt, by = dt[, unlist(lvl_list), with = FALSE])
数据
dt <- structure(list(meta_cat = c("bakery", "bakery", "bakery", "bakery",
"bakery", "fruits", "fruits", "fruits", "fruits"), cat = c("bread",
"bread", "doughnut", "sandwich", "sandwich", "feijoa", "orange",
"orange", "feijoa"), sku = c(796590L, 796595L, 796588L, 796640L,
796643L, 645342L, 645675L, 645677L, 645342L), price = c(22.6,
19.8, 30.6, 45.9, 43.3, 97.2, 35.7, 43.9, 92.9), sales = c(24L,
20L, 36L, 42L, 45L, 5L, 78L, 65L, 11L)), row.names = c(NA, -9L
), class = c("data.table", "data.frame"))
假设我有一个这样的数据集dt
:
meta_cat | cat | sku | price | sales |
---|---|---|---|---|
bakery | bread | 796590 | 22.6 | 24 |
bakery | bread | 796595 | 19.8 | 20 |
bakery | doughnut | 796588 | 30.6 | 36 |
bakery | sandwich | 796640 | 45.9 | 42 |
bakery | sandwich | 796643 | 43.3 | 45 |
fruits | feijoa | 645342 | 97.2 | 5 |
fruits | orange | 645675 | 35.7 | 78 |
fruits | orange | 645677 | 43.9 | 65 |
fruits | feijoa | 645342 | 92.9 | 11 |
此外,我有一个如下所示的列表,例如:
lvl_list <- list(c("meta_cat"),
c("cat"))
我事先不知道列表中会有多少层(列表长度可以是0(空列表),也可以是一、二、三等(在我们的例子中,有两个水平))。列表值对应于数据集中的列名称。
我的任务是运行基于列表长度的嵌套for循环。
如果列表为空,则不开始循环并执行main code
。
如果list length = 1,应该有1个这样的for循环:
for(i in unique(dt[[lvl_list[[1]]]])){
dt <- dt[get(lvl_list[[1]]) == I,] # make subset
# run main code
# .
# .
# main code
}
}
因此,在第一次迭代中,我们通过 meta_cat
列的第一个唯一值过滤 dt
(例如,仅选择 meta_cat = "bakery"
的记录)和 运行 main code
在此 dt
.
如果列表的长度 = 2,我们应该得到 2 个 for 循环:
for(i in unique(dt[[lvl_list[[1]]]])){
dt <- dt[get(lvl_list[[1]]) == i, ] # filter dt
for(j in unique(dt[[lvl_list[[2]]]])){
dt <- dt[get(lvl_list[[2]]) == j, ] # filter dt again
# run main code
# .
# .
# main code
}
}
所以,这里我们按两列的值过滤 dt
。
变量meta_cat
有2个唯一值,cat
变量有5个唯一值
代码执行的逻辑应该如下:在第一次迭代中,我们通过 meta_cat
的第一个值过滤 dt
(留在 dt
观察中,其中 meta_cat = "bakery"
) ,在第二个循环的第一次迭代中,我们通过 cat
变量的第一个值过滤 dt
(我们将选择 cat = "bread"
的观察值)。因此,我们得到 dt
,其中 meta_cat = "bakery"
和 cat = "bread"
。此外,此过滤后的 dt
用作建模代码的输入。
在第二次迭代中,原始 dt
被 meta_cat = "bakery"
和 cat = "doughnut"
过滤。然后主要代码执行到这个dt
,结束等等
如果列表中有 3 个级别,我们应该有 3 个 for 循环,等等
我的问题:是否可以根据列表长度动态创建嵌套 for 循环?
对于如何实施它的任何帮助,我将不胜感激。
使用 split
lst1 <- lapply(split(dt, dt[[lvl_list[[1]]]]), function(x)
split(x, x[[lvl_list[[2]]]]))
此外,由于这是一个递归拆分,使用 collapse
中的 rsplit
,默认情况下会进行递归拆分和 returns 嵌套列表`
library(collapse)
lst2 <- rsplit(dt, by = dt[, unlist(lvl_list), with = FALSE])
数据
dt <- structure(list(meta_cat = c("bakery", "bakery", "bakery", "bakery",
"bakery", "fruits", "fruits", "fruits", "fruits"), cat = c("bread",
"bread", "doughnut", "sandwich", "sandwich", "feijoa", "orange",
"orange", "feijoa"), sku = c(796590L, 796595L, 796588L, 796640L,
796643L, 645342L, 645675L, 645677L, 645342L), price = c(22.6,
19.8, 30.6, 45.9, 43.3, 97.2, 35.7, 43.9, 92.9), sales = c(24L,
20L, 36L, 42L, 45L, 5L, 78L, 65L, 11L)), row.names = c(NA, -9L
), class = c("data.table", "data.frame"))