如何在 R 中使用嵌套数据创建条件组标签?
How to create conditional group tags with nested data in R?
我的数据是这样的:
我有 5 个不同级别的嵌套数据:
- 类别(例如,“国家/地区”)
- 国家(例如“美国”)
- 城市(例如“纽约”)
- 县(例如“曼哈顿”)
- 地点(例如“时代广场”)
我的 df 中的每一行(LVL 1 条目除外)都链接到父级(更高级别)。例如:时代广场 -> 曼哈顿 -> 纽约 -> 美国 -> 国家
对于每个Name
,都有一个对应的n_values
列,表示数据条目的数量。
我的目标:我想组成>=8个数据条目的组。对于具有 n_values <8
的组,我想将它们与上一级的 Parent
列合并。这个新的分配应该用一个新的变量 new_group
.
来表达
首先从较低级别开始很重要!例如,“时代广场”只有 2 个数据条目,因此我们希望将这些条目与父“曼哈顿”合并。 Manhattan 现在有 3+2=5 个数据条目。这仍然是 <8,所以我们将这 5 个条目与下一个父“纽约”合并,后者现在有 16+5=21 个条目,所以我们很好。
我试过这样写一个循环:
for (i in 5:1){
df %>% filter(Level==i) %>% group_by(ID) %>% summarize(n = n())
但是,我未能将该信息与原始数据合并以创建我想要的数据集。有人可以帮忙吗?
数据:
structure(list(ID = c(19,12,3,41,50,6,77,83,9,105,11),
Parent = c(NA,19,12,3,41,12,19,77,77,19,105),
Level = c(1,2,3,4,5,3,2,3,3,2,3),
Name = c("Countries","USA","New York","Manhattan","Times Square",
"Boston","UK","London","Oxford","Canada","Vancouver"),
n_values = c(NA,17,16,3,2,13,12,7,8,9,8)),
class = "data.frame",
row.names = c(NA, -11L))
假设您的数据存储在名为 df
的数据框中。最直接的方法是首先将 table 的行按“Level”降序排列,然后将“new_group”设置为“Name”的值。我们还将在名为“new_values”的列中跟踪 per-group 总数。然后遍历行,直到遇到带有 new_values < 8
的行,此时该行的“new_group”更改为其父行的行,并且其“父级”也更新以匹配其父级的“亲”。那时,行循环重新开始。当没有“new_group”具有 new_values < 8
:
时,外循环终止
library(tidyverse)
df_sorted <- df %>%
arrange(desc(Level)) %>%
mutate(new_group = Name) %>%
group_by(new_group) %>%
mutate(new_values = sum(n_values)) %>%
ungroup
while (any(df_sorted$new_values < 8, na.rm = T)) {
for (i in 1:nrow(df_sorted)) {
if (df_sorted$new_values[i] < 8) {
to_id <- df_sorted$Parent[i]
to_row <- which(df_sorted$ID == to_id)
df_sorted$new_group[i] <- df_sorted$Name[to_row]
df_sorted$Parent[i] <- df_sorted$Parent[to_row]
df_sorted <- df_sorted %>%
group_by(new_group) %>%
mutate(new_values = sum(n_values)) %>%
ungroup
break # terminate the for loop immediately and return to the outer while loop
}
}
}
ID Parent Level Name n_values new_group new_values
<dbl> <dbl> <dbl> <chr> <dbl> <chr> <dbl>
1 50 12 5 Times Square 2 New York 21
2 41 12 4 Manhattan 3 New York 21
3 3 12 3 New York 16 New York 21
4 6 12 3 Boston 13 Boston 13
5 83 19 3 London 7 UK 19
6 9 77 3 Oxford 8 Oxford 8
7 11 105 3 Vancouver 8 Vancouver 8
8 12 19 2 USA 17 USA 17
9 77 19 2 UK 12 UK 19
10 105 19 2 Canada 9 Canada 9
11 19 NA 1 Countries NA Countries NA
编辑: 下面的版本添加了一个“touched”列来跟踪循环中已修改的行,还添加了一些对 NA
值的检查。对于上面使用的数据集,它产生与以前版本相同的结果。它在下面的数据集上似乎也能正常工作。
df <- structure(list(ID = c(19,12,3,41,50,6,77,83,9,105,11), Parent = c(NA,19,12,3,41,12,19,77,77,19,105), Level = c(1,2,3,4,5,3,2,3,3,2,3), Name = c("Countries","USA","New York","Manhattan","Times Square", "Boston","UK","London","Oxford","Canada","Vancouver"), n_values = c(NA,0,0,3,2,0,12,7,8,9,8)), class = "data.frame", row.names = c(NA, -11L))
df_sorted <- df %>%
arrange(desc(Level)) %>%
mutate(new_group = Name) %>%
group_by(new_group) %>%
mutate(
new_values = sum(n_values),
touched = is.na(n_values) | n_values >= 8
) %>%
ungroup
while (any(!df_sorted$touched)) {
for (i in 1:nrow(df_sorted)) {
if (df_sorted$new_values[i] < 8 & !is.na(df_sorted$Parent[i]) & any(!df_sorted$touched)) {
to_id <- df_sorted$Parent[i]
to_row <- which(df_sorted$ID == to_id)
df_sorted$new_group[i] <- df_sorted$Name[to_row]
df_sorted$Parent[i] <- df_sorted$Parent[to_row]
df_sorted$touched[i] <- TRUE
df_sorted <- df_sorted %>%
group_by(new_group) %>%
mutate(new_values = sum(n_values, na.rm = T)) %>%
ungroup
break # terminate the for loop immediately and return to the outer while loop
}
}
}
ID Parent Level Name n_values new_group new_values touched
<dbl> <dbl> <dbl> <chr> <dbl> <chr> <dbl> <lgl>
1 50 NA 5 Times Square 2 Countries 5 TRUE
2 41 NA 4 Manhattan 3 Countries 5 TRUE
3 3 NA 3 New York 0 Countries 5 TRUE
4 6 NA 3 Boston 0 Countries 5 TRUE
5 83 19 3 London 7 UK 19 TRUE
6 9 77 3 Oxford 8 Oxford 8 TRUE
7 11 105 3 Vancouver 8 Vancouver 8 TRUE
8 12 NA 2 USA 0 Countries 5 TRUE
9 77 19 2 UK 12 UK 19 TRUE
10 105 19 2 Canada 9 Canada 9 TRUE
11 19 NA 1 Countries NA Countries 5 TRUE
我的数据是这样的:
我有 5 个不同级别的嵌套数据:
- 类别(例如,“国家/地区”)
- 国家(例如“美国”)
- 城市(例如“纽约”)
- 县(例如“曼哈顿”)
- 地点(例如“时代广场”)
我的 df 中的每一行(LVL 1 条目除外)都链接到父级(更高级别)。例如:时代广场 -> 曼哈顿 -> 纽约 -> 美国 -> 国家
对于每个Name
,都有一个对应的n_values
列,表示数据条目的数量。
我的目标:我想组成>=8个数据条目的组。对于具有 n_values <8
的组,我想将它们与上一级的 Parent
列合并。这个新的分配应该用一个新的变量 new_group
.
首先从较低级别开始很重要!例如,“时代广场”只有 2 个数据条目,因此我们希望将这些条目与父“曼哈顿”合并。 Manhattan 现在有 3+2=5 个数据条目。这仍然是 <8,所以我们将这 5 个条目与下一个父“纽约”合并,后者现在有 16+5=21 个条目,所以我们很好。
我试过这样写一个循环:
for (i in 5:1){
df %>% filter(Level==i) %>% group_by(ID) %>% summarize(n = n())
但是,我未能将该信息与原始数据合并以创建我想要的数据集。有人可以帮忙吗?
数据:
structure(list(ID = c(19,12,3,41,50,6,77,83,9,105,11),
Parent = c(NA,19,12,3,41,12,19,77,77,19,105),
Level = c(1,2,3,4,5,3,2,3,3,2,3),
Name = c("Countries","USA","New York","Manhattan","Times Square",
"Boston","UK","London","Oxford","Canada","Vancouver"),
n_values = c(NA,17,16,3,2,13,12,7,8,9,8)),
class = "data.frame",
row.names = c(NA, -11L))
假设您的数据存储在名为 df
的数据框中。最直接的方法是首先将 table 的行按“Level”降序排列,然后将“new_group”设置为“Name”的值。我们还将在名为“new_values”的列中跟踪 per-group 总数。然后遍历行,直到遇到带有 new_values < 8
的行,此时该行的“new_group”更改为其父行的行,并且其“父级”也更新以匹配其父级的“亲”。那时,行循环重新开始。当没有“new_group”具有 new_values < 8
:
library(tidyverse)
df_sorted <- df %>%
arrange(desc(Level)) %>%
mutate(new_group = Name) %>%
group_by(new_group) %>%
mutate(new_values = sum(n_values)) %>%
ungroup
while (any(df_sorted$new_values < 8, na.rm = T)) {
for (i in 1:nrow(df_sorted)) {
if (df_sorted$new_values[i] < 8) {
to_id <- df_sorted$Parent[i]
to_row <- which(df_sorted$ID == to_id)
df_sorted$new_group[i] <- df_sorted$Name[to_row]
df_sorted$Parent[i] <- df_sorted$Parent[to_row]
df_sorted <- df_sorted %>%
group_by(new_group) %>%
mutate(new_values = sum(n_values)) %>%
ungroup
break # terminate the for loop immediately and return to the outer while loop
}
}
}
ID Parent Level Name n_values new_group new_values
<dbl> <dbl> <dbl> <chr> <dbl> <chr> <dbl>
1 50 12 5 Times Square 2 New York 21
2 41 12 4 Manhattan 3 New York 21
3 3 12 3 New York 16 New York 21
4 6 12 3 Boston 13 Boston 13
5 83 19 3 London 7 UK 19
6 9 77 3 Oxford 8 Oxford 8
7 11 105 3 Vancouver 8 Vancouver 8
8 12 19 2 USA 17 USA 17
9 77 19 2 UK 12 UK 19
10 105 19 2 Canada 9 Canada 9
11 19 NA 1 Countries NA Countries NA
编辑: 下面的版本添加了一个“touched”列来跟踪循环中已修改的行,还添加了一些对 NA
值的检查。对于上面使用的数据集,它产生与以前版本相同的结果。它在下面的数据集上似乎也能正常工作。
df <- structure(list(ID = c(19,12,3,41,50,6,77,83,9,105,11), Parent = c(NA,19,12,3,41,12,19,77,77,19,105), Level = c(1,2,3,4,5,3,2,3,3,2,3), Name = c("Countries","USA","New York","Manhattan","Times Square", "Boston","UK","London","Oxford","Canada","Vancouver"), n_values = c(NA,0,0,3,2,0,12,7,8,9,8)), class = "data.frame", row.names = c(NA, -11L))
df_sorted <- df %>%
arrange(desc(Level)) %>%
mutate(new_group = Name) %>%
group_by(new_group) %>%
mutate(
new_values = sum(n_values),
touched = is.na(n_values) | n_values >= 8
) %>%
ungroup
while (any(!df_sorted$touched)) {
for (i in 1:nrow(df_sorted)) {
if (df_sorted$new_values[i] < 8 & !is.na(df_sorted$Parent[i]) & any(!df_sorted$touched)) {
to_id <- df_sorted$Parent[i]
to_row <- which(df_sorted$ID == to_id)
df_sorted$new_group[i] <- df_sorted$Name[to_row]
df_sorted$Parent[i] <- df_sorted$Parent[to_row]
df_sorted$touched[i] <- TRUE
df_sorted <- df_sorted %>%
group_by(new_group) %>%
mutate(new_values = sum(n_values, na.rm = T)) %>%
ungroup
break # terminate the for loop immediately and return to the outer while loop
}
}
}
ID Parent Level Name n_values new_group new_values touched
<dbl> <dbl> <dbl> <chr> <dbl> <chr> <dbl> <lgl>
1 50 NA 5 Times Square 2 Countries 5 TRUE
2 41 NA 4 Manhattan 3 Countries 5 TRUE
3 3 NA 3 New York 0 Countries 5 TRUE
4 6 NA 3 Boston 0 Countries 5 TRUE
5 83 19 3 London 7 UK 19 TRUE
6 9 77 3 Oxford 8 Oxford 8 TRUE
7 11 105 3 Vancouver 8 Vancouver 8 TRUE
8 12 NA 2 USA 0 Countries 5 TRUE
9 77 19 2 UK 12 UK 19 TRUE
10 105 19 2 Canada 9 Canada 9 TRUE
11 19 NA 1 Countries NA Countries 5 TRUE