【问题标题】:By group, sort and assign total to highest ranking item and 0 to rest按组,排序并分配总到最高排名的项目,0 到休息
【发布时间】:2018-01-17 02:23:43
【问题描述】:

我的目标是在美国各县的基础地图上绘制大都会统计区(MSA 或 CBSA)及其人口。 MSA 县将带有阴影,非 MSA 县将留空(基本等值线图)。 MSA 总人口将由以各个 MSA 人口最多的县为中心的比例圆圈表示。我正在处理基础数据并遇到了障碍。

数据在一个超过 1000 行的 df 中,其中这个示例:

head(pop_2010_map[order(pop_2010_map$cbsa_code),], 5)
    cbsa_code cbsa_name county_code_long Population
936     10180   Abilene            48059      13544
967     10180   Abilene            48253      20202
993     10180   Abilene            48441     131506
765     10420     Akron            39133     161419
768     10420     Akron            39153     541781

我需要按 cbsa_code 聚合人口,并将总数分配给每个 cbsa_code 中最大(最高人口)county_code_long 和剩余的county_code_long 0。

预期的结果应该是这样的:

    cbsa_code cbsa_name county_code_long Population
936     10180   Abilene            48059          0
967     10180   Abilene            48253          0
993     10180   Abilene            48441     165252
765     10420     Akron            39133          0
768     10420     Akron            39153     703200

感谢您的帮助!

【问题讨论】:

    标签: r gis


    【解决方案1】:

    您可以通过使用dplyr 的函数group_by()mutate() 以及ifelse 语句来实现这一点,如下所示:

    # Load library
    library(dplyr)
    
    # Create example data.frame
    x <- read.table(text = 
    "cbsa_code cbsa_name county_code_long Population
    936     10180   Abilene            48059      13544
    967     10180   Abilene            48253      20202
    993     10180   Abilene            48441     131506
    765     10420     Akron            39133     161419
    768     10420     Akron            39153     541781")
    
    # Desired result
    new_x <- x %>% 
      group_by(cbsa_code) %>% 
      mutate(Population = ifelse(Population == max(Population), 
                                 sum(Population), 0)) %>% 
      ungroup()
    

    结果如下:

    # A tibble: 5 x 4
      cbsa_code cbsa_name county_code_long Population
          <int>    <fctr>            <int>      <dbl>
    1     10180   Abilene            48059          0
    2     10180   Abilene            48253          0
    3     10180   Abilene            48441     165252
    4     10420     Akron            39133          0
    5     10420     Akron            39153     703200
    

    更新:

    假设有两个县处于平局,两个县的人口都最多(我刚刚为阿克伦添加了一个示例):

    # Create example data.frame
    y <- read.table(text = 
                      "cbsa_code cbsa_name county_code_long Population
    936     10180   Abilene            48059      13544
    967     10180   Abilene            48253      20202
    993     10180   Abilene            48441     131506
    765     10420     Akron            39133     161419
    768     10420     Akron            39153     541781
    769     10420     Akron            39154     541781")
    

    在这种情况下,如果我们应用上面的代码...

    y %>% 
      group_by(cbsa_code) %>% 
      mutate(Population = ifelse(Population == max(Population), 
                                 sum(Population), 0)) %>% 
      ungroup()
    

    ...我们得到两个关于“阿克伦”县的条目

    # A tibble: 6 x 4
      cbsa_code cbsa_name county_code_long Population
          <int>    <fctr>            <int>      <dbl>
    1     10180   Abilene            48059          0
    2     10180   Abilene            48253          0
    3     10180   Abilene            48441     165252
    4     10420     Akron            39133          0
    5     10420     Akron            39153    1244981
    6     10420     Akron            39154    1244981
    

    如果您想要带有零的完整表格,这里有一个解决方案(请参阅 this dplyr vignette 有关该方法的更多信息):

    # Rank the Population values according to their descending order, so that the 
    ## one with maximum is ranked 1 (if there are ties, only one of them is chosen).
    y %>% 
      group_by(cbsa_code) %>% 
      mutate(pop_rank = row_number(desc(Population)),
             Population = ifelse(pop_rank == 1, 
                                 sum(Population), 0)) %>% 
      ungroup() %>% 
      select(-pop_rank)
    

    导致:

    # A tibble: 6 x 4
      cbsa_code cbsa_name county_code_long Population
          <int>    <fctr>            <int>      <dbl>
    1     10180   Abilene            48059          0
    2     10180   Abilene            48253          0
    3     10180   Abilene            48441     165252
    4     10420     Akron            39133          0
    5     10420     Akron            39153    1244981
    6     10420     Akron            39154          0
    

    如果你只想保留人口最多的县,你可以使用 summarise()这样(随意取第一个county_code_long):

    y %>% 
      group_by(cbsa_code, cbsa_name) %>% 
      summarise(Population = sum(Population), 
                county_code_long = county_code_long[1]) %>% 
      ungroup()
    

    导致:

    # A tibble: 2 x 4
      cbsa_code cbsa_name Population county_code_long
          <int>    <fctr>      <int>            <int>
    1     10180   Abilene     165252            48059
    2     10420     Akron    1244981            39133
    

    【讨论】:

    • 谢谢!但是,我需要将组总人口分配给具有组中最高人口的项目。我相信您所做的只是将 0 分配给非排名靠前的代码。我已经调整了你的代码,我认为这可行:new_x &lt;- x %&gt;% group_by(cbsa_code) %&gt;% mutate(Population = ifelse(Population == max(Population), sum(Population), 0)) %&gt;% ungroup()
    • @syre 对不起,你说得对!我已经更正了答案。另外,顺便说一句,如果您实际上对保留另一个 county_code_long 不感兴趣,您可以使用 x %&gt;% group_by(cbsa_code, cbsa_name) %&gt;% summarise(Population = sum(Population), county_code_long = max(county_code_long)) %&gt;% ungroup()
    • @syre 还请注意,如果每个cbsa_code 有多个max(county_code_long),则实际上每个cbsa_code 将获得多个结果。我认为确保每个cbsa_code 只有一个结果的一种方法是在命令管道的末尾添加distinct()
    • 我不是想对county_code_long(这是一个id 代码)进行排名,而是对Population 进行排名,所以您的代码仍然有一点偏差。请参阅我的解决方案。你是对的,我们应该避免联系,所以请添加distinct()。如果我知道确切的位置,我会自己做。
    • @syre 再次抱歉!我希望这次我做对了...我已经对其进行了修改并扩展了答案以处理最大人口中可能存在的联系(distinct() 的想法毕竟不太奏效!)。我希望这是有道理的。
    【解决方案2】:
     x <- read.table(text = 
                  "cbsa_code cbsa_name county_code_long Population
                936     10180   Abilene            48059      13544
                967     10180   Abilene            48253      20202
                993     10180   Abilene            48441     131506
                765     10420     Akron            39133     161419
                768     10420     Akron            39153     541781")
    

    使用简单的基函数。 (我已经简化了,所以不是一般问题)

       a=mapply(tapply,list(x$Population),list(x$cbsa_code),c(sum,which.max))
       x$Population=0;x$Population[cumsum(a[,2])]=a[,1]
       x
                  cbsa_code cbsa_name county_code_long  Population
      936            10180    Abilene            48059          0
      967            10180    Abilene            48253          0
      993            10180    Abilene            48441     165252
      765            10420      Akron            39133          0
      768            10420      Akron            39153     703200
    

    【讨论】:

    • 谢谢,但这不适用于我更大的数据集。例如,有些组以 0 结尾,而另一些组则以多个非 0 数字结尾。
    • 实际上我在写之前就警告过你了......我把它简化了......只是让你知道如何去做。也许我可以尝试写一个通用格式代码
    • 非常感谢您的好意,但我已经在我对第一个答案的评论中找到了解决方案,所以不要在这方面浪费太多时间。
    猜你喜欢
    • 2023-01-26
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 2011-06-03
    • 1970-01-01
    相关资源
    最近更新 更多