根据值对一列求和,然后根据性别按降序排序

时间:2019-09-13 01:05:33

标签: r

我试图找到在过去几年中排名前五位的最常见名字,按男性/女性划分。这是来自R中的“ babynames”软件包。

我有这个有效的代码:

babynames %>%
  group_by(sex, name) %>%
  summarize(total = sum(n)) %>%
  arrange(desc(total)) %$%
  split(., sex)

哪个产生以下输出:

# A tibble: 67,046 x 3
# Groups:   sex [1]
   sex   name        total
   <chr> <chr>       <int>
 1 F     Mary      4123200
 2 F     Elizabeth 1629679
 3 F     Patricia  1571692
 4 F     Jennifer  1466281
 5 F     Linda     1452249
 6 F     Barbara   1434060
 7 F     Margaret  1246649
 8 F     Susan     1121440
 9 F     Dorothy   1107096
10 F     Sarah     1073895
# … with 67,036 more rows

$M
# A tibble: 40,927 x 3
# Groups:   sex [1]
   sex   name      total
   <chr> <chr>     <int>
 1 M     James   5150472
 2 M     John    5115466
 3 M     Robert  4814815
 4 M     Michael 4350824
 5 M     William 4102604
 6 M     David   3611329
 7 M     Joseph  2603445
 8 M     Richard 2563082
 9 M     Charles 2386048
10 M     Thomas  2304948
# … with 40,917 more rows

但是我也需要找到另一种方法。

这是我想出的,但是我不能让它等于上面代码中的数字:

summary <- babynames %>% group_by(sex, name) %>% split(., sex)
summaryFemales <- summary$F
summaryFemales
summaryFemales1 <- summarize(summaryFemales, net=sum(n))
summaryFemales1
head(summaryFemales1, 10)

在这里,第一行基于此人是男性还是女性,成功地对数据进行分组和拆分。然后,我尝试制作摘要的子集,称为summaryFemales,以仅显示女性数据。然后,我尝试使用summary()来添加名称在每年出现的所有时间,但结果是:

# A tibble: 67,046 x 3
# Groups:   sex [1]
   sex   name        net
   <chr> <chr>     <int>
 1 F     Aabha        35
 2 F     Aabriella    32
 3 F     Aada          5
 4 F     Aaden         5
 5 F     Aadhira      77
 6 F     Aadhvika      9
 7 F     Aadhya     1478
 8 F     Aadi         16
 9 F     Aadilynn      5
10 F     Aadison      11
# … with 67,036 more rows

然后我尝试通过使用head()获得前10个最高值来完成此操作,但这会产生与上面的行相同的结果。

我也尝试过这个add_count()函数,它吐出相同的n值,这太高了:

> add_count(babynames, wt=NULL, sort = FALSE, name = "n")
# A tibble: 1,924,665 x 5
    year sex   name            n   prop
   <dbl> <chr> <chr>       <int>  <dbl>
 1  1880 F     Mary      1924665 0.0724
 2  1880 F     Anna      1924665 0.0267
 3  1880 F     Emma      1924665 0.0205
 4  1880 F     Elizabeth 1924665 0.0199
 5  1880 F     Minnie    1924665 0.0179
 6  1880 F     Margaret  1924665 0.0162
 7  1880 F     Ida       1924665 0.0151
 8  1880 F     Alice     1924665 0.0145
 9  1880 F     Bertha    1924665 0.0135
10  1880 F     Sarah     1924665 0.0132
# … with 1,924,655 more rows

任何帮助将不胜感激。谢谢

2 个答案:

答案 0 :(得分:3)

既然您询问了“另一种方法”,那么基本R解决方案(不需要外部库)如何?

lst <- lapply(
    split(babynames, babynames$sex),
    function(x) {
        df <- aggregate(n ~ name, data = x, FUN = sum)
        df[order(df$n, decreasing = T)[1:5], ]
    })
lst
#$F
#           name       n
#41738      Mary 4123200
#18700 Elizabeth 1629679
#48449  Patricia 1571692
#27718  Jennifer 1466281
#37748     Linda 1452249
#
#$M
#         name       n
#17080   James 5150472
#19152    John 5115466
#32106  Robert 4814815
#26918 Michael 4350824
#39123 William 4102604

这将返回list中的data.frame;如果您更喜欢一个data.frame,则可以

do.call(rbind, lst)
#             name       n
#F.41738      Mary 4123200
#F.18700 Elizabeth 1629679
#F.48449  Patricia 1571692
#F.27718  Jennifer 1466281
#F.37748     Linda 1452249
#M.17080     James 5150472
#M.19152      John 5115466
#M.32106    Robert 4814815
#M.26918   Michael 4350824
#M.39123   William 4102604

答案 1 :(得分:2)

如果您要查找帖子第一行中提到的几年内最常见的前5名(按男性/女性划分)。您可以执行以下操作:filter指定年份的数据,group_by sexname并计算sum的{​​{1}}并得到每个n的前5个值。

sex

我们可以将以上翻译成基数R

library(dplyr)
library(babynames)

start_year <- 1950
end_year <- 2000

babynames %>%
  filter(year >= start_year & year <= end_year) %>%
  group_by(sex, name) %>%
  summarise(n = sum(n)) %>%
  top_n(5, n)


#   sex   name           n
#   <chr> <chr>      <int>
# 1 F     Jennifer 1387519
# 2 F     Jessica   949989
# 3 F     Linda     872107
# 4 F     Lisa      952589
# 5 F     Mary     1284713
# 6 M     David    2606708
# 7 M     James    2592627
# 8 M     John     2495291
# 9 M     Michael  3536082
#10 M     Robert   2419214