按阈值过滤数据,包括超过阈值的第一值

时间:2018-08-13 17:12:32

标签: r dplyr

这似乎是一个简单的问题,但是我无法解决这个问题。我有一个按出生地区划分的人口分布位置的数据框,我正在尝试筛选人口总数超过阈值(在本例中为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%的位置。不过,我将保留此内容,以帮助那些无法以这种方式控制其数据的人。

1 个答案:

答案 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技能。