这似乎是一个简单的问题,但是我无法解决这个问题。我有一个按出生地区划分的人口分布位置的数据框,我正在尝试筛选人口总数超过阈值(在本例中为50%)的区域。
例如,对于每个地点,我需要能够说出这样的话:“在费尔菲尔德县,大多数外国出生人口出生于中美洲,南美洲或加勒比海。”为了能够这样说,我需要包括第一个超过50%的国家。
我的数据的节略版本以及每个位置的前几行在这里:
library(tidyverse)
df <- structure(list(name = c("Fairfield County", "Fairfield County",
"Fairfield County", "Fairfield County", "Greater Hartford", "Greater Hartford",
"Greater Hartford", "Greater Hartford", "Greater Hartford"),
subregion = c("South America", "Central America", "Caribbean",
"South Central Asia", "Caribbean", "Eastern Europe", "South Central Asia",
"South America", "Southern Europe"),
pop = c(40565, 33919, 32044, 17031, 26939, 23765, 20153, 14384, 9309),
cum_share = c(0.2, 0.38, 0.54, 0.62, 0.2, 0.37, 0.51, 0.62, 0.69)),
class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -9L))
df %>%
group_by(name) %>%
top_n(4, pop)
#> # A tibble: 8 x 4
#> # Groups: name [2]
#> name subregion pop cum_share
#> <chr> <chr> <dbl> <dbl>
#> 1 Fairfield County South America 40565 0.2
#> 2 Fairfield County Central America 33919 0.38
#> 3 Fairfield County Caribbean 32044 0.54
#> 4 Fairfield County South Central Asia 17031 0.62
#> 5 Greater Hartford Caribbean 26939 0.2
#> 6 Greater Hartford Eastern Europe 23765 0.37
#> 7 Greater Hartford South Central Asia 20153 0.51
#> 8 Greater Hartford South America 14384 0.62
我的第一个计划是过滤累积份额小于或等于51%的区域,这意味着排名靠前的区域,直到达到人口的大多数。这样做的问题是,因为这些份额不是连续分布,所以具有这样的设定截止点是行不通的,因为我需要包括累积份额占多数的第一个区域。
df %>%
filter(cum_share <= 0.51)
#> # A tibble: 5 x 4
#> name subregion pop cum_share
#> <chr> <chr> <dbl> <dbl>
#> 1 Fairfield County South America 40565 0.2
#> 2 Fairfield County Central America 33919 0.38
#> 3 Greater Hartford Caribbean 26939 0.2
#> 4 Greater Hartford Eastern Europe 23765 0.37
#> 5 Greater Hartford South Central Asia 20153 0.51
通过与第一个快照进行比较可以看到,Greater Hartford的工作与我期望的一样。但是,费尔菲尔德县应包括加勒比地区,其累计份额为54%;通过设置为51%的阈值进行过滤,则不包括加勒比海地区。我想得到的是这样的:
#> # A tibble: 6 x 4
#> name subregion pop cum_share
#> <chr> <chr> <dbl> <dbl>
#> 1 Fairfield County South America 40565 0.2
#> 2 Fairfield County Central America 33919 0.38
#> 3 Fairfield County Caribbean 32044 0.54
#> 4 Greater Hartford Caribbean 26939 0.2
#> 5 Greater Hartford Eastern Europe 23765 0.37
#> 6 Greater Hartford South Central Asia 20153 0.51
在此,份额超过50%的位置也包括在内。我可以手动进行过滤,但是实际上我是按国家/地区而不是世界各地进行过滤的,并且针对18个位置,因此变得难以处理。
谢谢!
编辑:哇,我正在意识到自己的愚蠢-我可以按升顺序而不是降来计算人口的累积份额,然后轻松过滤此阈值超过50%的位置。不过,我将保留此内容,以帮助那些无法以这种方式控制其数据的人。
答案 0 :(得分:4)
例如,对于每个地点,我需要能够说出这样的话:“在费尔菲尔德县,大多数外国出生的人口出生在中南美洲或加勒比海地区。”
对于满足条件后停止的一般情况,有filter(lag(cumsum(cond), default=FALSE) == 0)
> df %>% group_by(name) %>% filter(cumsum(lag(cum_share > 0.5, default = FALSE)) == 0)
# A tibble: 6 x 4
# Groups: name [2]
name subregion pop cum_share
<chr> <chr> <dbl> <dbl>
1 Fairfield County South America 40565 0.20
2 Fairfield County Central America 33919 0.38
3 Fairfield County Caribbean 32044 0.54
4 Greater Hartford Caribbean 26939 0.20
5 Greater Hartford Eastern Europe 23765 0.37
6 Greater Hartford South Central Asia 20153 0.51
在单调情况下,OP识别出一个更简单的过滤器(即,一个过滤器首先满足该条件后,向量的后继元素也可以这样做):filter(lag(cum_share, default = 0) <= 0.5)
。
可能有个好方法可以将其包装在一个函数中(从用户输入中将.cond
进行突变;对.keep
的条件进行= cumsum(lag(.cond, default=FALSE) == 0)
进行过滤;过滤器;将.cond
和{{1 }}),但第一步我没有整洁的NSE技能。