• The Popularity of Baby Names
    • Question 1
      • Part A
      • Part B
    • Question 2
    • Question 3
    • Question 4
    • Question 5
      • Part A
      • Part B
    • Question 6
      • Part A
      • Part B
    • Question 7
  • Political and Economic Freedom Around the World
    • Question 8
    • Question 9
    • Question 10
    • Question 11
    • Question 12
    • Question 13

Answers may be longer than I would deem sufficient on an exam. Some might vary slightly based on points of interest, examples, or personal experience. These suggested answers are designed to give you both the answer and a short explanation of why it is the answer.

The Popularity of Baby Names

Install and load the package babynames. Get help for ?babynames to see what the data includes.

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 3.2.0     ✔ purrr   0.3.2
## ✔ tibble  2.1.3     ✔ dplyr   0.8.3
## ✔ tidyr   1.0.0     ✔ stringr 1.4.0
## ✔ readr   1.3.1     ✔ forcats 0.4.0
## ── Conflicts ────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
# install for first use
# install.packages("babynames")

# load package 
library(babynames)

# explore help
# ?babynames

Question 1

Part A

What are the top 5 boys names for 2017, and what percent of overall names is each?

# save as a new tibble
top_5_boys_2017 <- babynames %>% # take data
  filter(sex=="M", # filter by males
         year==2017) %>% # and for 2007
  arrange(desc(n)) %>% # arrange in largest-to-smallest order of n (number)
  slice(1:5) %>% # optional, look only at first 5 rows; head(., n=5) also works
  mutate(percent = round(prop*100, 2)) # also optional, make a percent variable rounded to 2 decimals

# look at our new tibble
top_5_boys_2017
ABCDEFGHIJ0123456789
year
<dbl>
sex
<chr>
name
<chr>
n
<int>
prop
<dbl>
percent
<dbl>
2017MLiam187280.009539090.95
2017MNoah183260.009334330.93
2017MWilliam149040.007591340.76
2017MJames142320.007249060.72
2017MLogan139740.007117640.71

The top 5 names are

  1. Liam (0.95%)
  2. Noah (0.93%)
  3. William (0.76%)
  4. James (0.72%)
  5. Logan (0.71%)

Part B

What are the top 5 girls names, and what percent of overall names is each?

# save as a new tibble
top_5_girls_2017 <- babynames %>% # take data
  filter(sex=="F", # filter by females
         year==2017) %>% # and for 2007
  arrange(desc(n)) %>% # arrange in largest-to-smallest order of n (number)
  slice(1:5) %>% # optional, look only at first 5 rows; head(., n=5) also works
  mutate(percent = round(prop*100, 2)) # also optional, make a percent variable rounded to 2 decimals

# look at our new tibble
top_5_girls_2017
ABCDEFGHIJ0123456789
year
<dbl>
sex
<chr>
name
<chr>
n
<int>
prop
<dbl>
percent
<dbl>
2017FEmma197380.010527501.05
2017FOlivia186320.009937600.99
2017FAva159020.008481520.85
2017FIsabella151000.008053770.81
2017FSophia148310.007910290.79

The top 5 names are

  1. Emma (1.05%)
  2. Olivia (0.99%)
  3. Ava (0.85%)
  4. Isabella (0.81%)
  5. Sophia (0.79%)

Question 2

Make two barplots, of these top 5 names, one for each sex. Map aesthetics x to name and y to prop1 and use geom_col (since you are declaring a specific y, otherwise you could just use geom_bar() and just an x.)

ggplot(data = top_5_boys_2017)+
  aes(x = reorder(name, n), #note this reorders the x variable from small to large n
      y = percent, # you can use prop if you didn't make a percent variable
      fill = name)+ # optional color!
  geom_col()+
  
  # now I'm just making it pretty
  scale_y_continuous(labels=function(x)paste(x,"%",sep=""))+ # optional, add percent signs
      labs(x = "Name",
         y = "Percent of All Babies With Name",
         title = "Most Popular Boys Names Since 1880",
         fill = "Boy's Name",
         caption = "Source: SSA")+
    theme_classic(base_family = "Fira Sans Condensed", base_size=16)+
  coord_flip()+ # rotate axes!
  theme(legend.position = "") # hide legend

ggplot(data = top_5_girls_2017)+
  aes(x = reorder(name, n), #note this reorders the x variable from small to large n
      y = percent, # you can use prop if you didn't make a percent variable
      fill = name)+ # optional color!
  geom_col()+
  # now I'm just making it pretty
  scale_y_continuous(labels=function(x)paste(x,"%",sep=""))+ # optional, add percent signs
      labs(x = "Name",
         y = "Percent of All Girls With Name",
         title = "Most Popular Girls Names Since 1880",
         fill = "Girl's Name",
         caption = "Source: SSA")+
    theme_classic(base_family = "Fira Sans Condensed", base_size=16)+
  coord_flip()+ # rotate axes!
  theme(legend.position = "") # hide legend

Question 3

Find your name.2 count by sex how many babies since 1880 were named your name.3 Also add a variable for the percent of each sex.

babynames %>%
  filter(name == "Ryan") %>%
  count(sex, wt=n) %>%
  mutate(percent = round((n/sum(n)*100),2))
ABCDEFGHIJ0123456789
sex
<chr>
n
<int>
percent
<dbl>
F229102.42
M92487797.58

Question 4

Make a line graph of the number of babies with your name over time, colored by sex.

# note here I'm going to wrangle the data and then pipe it directly into ggplot
# you can wrangle the data and save it as a different tibble, then use THAT tibble
# for your (data = ...) command in ggplot

# first wrangle data
babynames %>%
  filter(name == "Ryan") %>%

  # now we pipe into ggplot
  ggplot(data = .)+ # the "." is a placeholder for the stuff above!
  aes(x = year,
      y = n,
      color = sex)+
  geom_line(size=1)+
  labs(x = "Year",
       y = "Number of Babies",
       title = "Popularity of Babies Named 'Ryan'",
       color = "Sex",
       caption = "Source: SSA")+
    theme_classic(base_family = "Fira Sans Condensed", base_size=16)

Question 5

Part A

Make a table of the most common name for boys by year between 1980-2017.4

babynames %>%
  group_by(year) %>% # we want one observation per year
  filter(sex == "M",
         year>1979) %>% # or >==1980
  arrange(desc(n))%>% # start with largest n first
  slice(1) # take first row only
ABCDEFGHIJ0123456789
year
<dbl>
sex
<chr>
name
<chr>
n
<int>
prop
<dbl>
1980MMichael686930.03703079
1981MMichael687650.03692247
1982MMichael682280.03615445
1983MMichael679950.03649110
1984MMichael677360.03610228
1985MMichael649060.03373805
1986MMichael642050.03342343
1987MMichael636470.03264834
1988MMichael641330.03204521
1989MMichael653820.03120182

Part B

Now do the same for girls.

babynames %>%
  group_by(year) %>% # we want one observation per year
  filter(sex == "F",
         year>1979) %>% # or >==1980
  arrange(desc(n))%>% # start with largest n first
  slice(1) # take first row only
ABCDEFGHIJ0123456789
year
<dbl>
sex
<chr>
name
<chr>
n
<int>
prop
<dbl>
1980FJennifer583760.03278886
1981FJennifer570490.03190242
1982FJennifer571150.03148593
1983FJennifer543420.03036962
1984FJennifer505610.02804442
1985FJessica483460.02619098
1986FJessica526740.02854888
1987FJessica559910.02988050
1988FJessica515380.02680669
1989FJessica478850.02403998

Question 6

Now let’s graph the evolution of the most common names since 1880.

Part A

First, find out what are the top 10 overall most popular names for boys and for girls. You may want to create two vectors, each with these top 5 names.

babynames %>%
  group_by(name) %>% # we want one row per name
  filter(sex=="M") %>%
  summarize(total=sum(n)) %>% # add upp all of the n's for all years for each name
  arrange(desc(total)) %>% # list largest total first
  slice(1:5) 
ABCDEFGHIJ0123456789
name
<chr>
total
<int>
James5150472
John5115466
Robert4814815
Michael4350824
William4102604
# make a vector of the names (we'll need this for our graph below)
top_boys_names<-c("James", "John", "Robert", "Michael", "William")

# you could alternatively add a command, 
# %>% pull(name) to the first chunk of code, 
# and it would do the same thing, but we'd want to save it, 
# for example:

babynames %>%
  group_by(name) %>% # we want one row per name
  filter(sex=="M") %>%
  summarize(total=sum(n)) %>% # add upp all of the n's for all years for each name
  arrange(desc(total)) %>% # list largest total first
  slice(1:5) %>%
  pull(name)
## [1] "James"   "John"    "Robert"  "Michael" "William"
babynames %>%
  group_by(name) %>% # we want one row per name
  filter(sex=="F") %>%
  summarize(total=sum(n)) %>% # add upp all of the n's for all years for each name
  arrange(desc(total)) %>% # list largest total first
  slice(1:5)
ABCDEFGHIJ0123456789
name
<chr>
total
<int>
Mary4123200
Elizabeth1629679
Patricia1571692
Jennifer1466281
Linda1452249
# make a vector of the names (we'll need this for our graph below)
top_girls_names<-c("Mary", "Elizabeth", "Patricia", "Jennifer", "Linda")

Part B

Now make two linegraphs of these 5 names over time, one for boys, and one for girls.

babynames %>%
  group_by(year) %>%
  filter(sex == "M",
         name %in% top_boys_names) %>%
  ggplot(data = .,
         aes(x = year,
             y = prop,
             color = name))+
  geom_line()+
      labs(x = "Year",
         y = "Proportion of Babies with Name",
         title = "Most Popular Boys Names Since 1880",
         color = "Boy's Name",
         caption = "Source: SSA")+
    theme_classic(base_family = "Fira Sans Condensed", base_size=16)

babynames %>%
  group_by(year) %>%
  filter(sex == "F",
         name %in% top_girls_names) %>%
  ggplot(data = .,
         aes(x = year,
             y = prop,
             color = name))+
  geom_line()+
    labs(x = "Year",
         y = "Proportion of Babies with Name",
         title = "Most Popular Girls Names Since 1880",
         color = "Girl's Name",
         caption = "Source: SSA")+
    theme_classic(base_family = "Fira Sans Condensed", base_size=16)

Question 7

Bonus (hard!): What are the 10 most common “gender-neutral” names?5

There’s a lot to this, so I’ll break this up step by step and show you what happens at each major step.

We want to find the names where 48% to 52% of the babies with the name are male, as I defined in the footnote. First let’s mutate a variable to figure out how many babies with a particular name are male.

To do this, we’ll need to make a two variables to count the number of males and females of each name each year. We’ll use the ifelse() function for each:

  1. Make a male variable where, for each name in each year, if sex=="M", then count the number of males (n) that year, otherwise set it equal to 0.
  2. Make a female variable where, for each name in each year, if sex=="F", then count the number of females (n) that year, otherwise set it equal to 0.
babynames %>%
  mutate(male = ifelse(sex == "M", n, 0),
         female = ifelse(sex == "F", n, 0))
ABCDEFGHIJ0123456789
year
<dbl>
sex
<chr>
name
<chr>
n
<int>
prop
<dbl>
male
<dbl>
female
<dbl>
1880FMary70650.0723835907065
1880FAnna26040.0266789602604
1880FEmma20030.0205214902003
1880FElizabeth19390.0198657901939
1880FMinnie17460.0178884301746
1880FMargaret15780.0161672001578
1880FIda14720.0150811901472
1880FAlice14140.0144869601414
1880FBertha13200.0135239001320
1880FSarah12880.0131960501288

Now with this variable, we want to count the total number of males and females with each name over the entire dataset. Let’s first group_by(name) so we’ll get one row for every name. We will summarize() and take the sum of our male and of our female variables.

babynames %>%
  mutate(male = ifelse(sex == "M", n, 0),
         female = ifelse(sex == "F", n, 0)) %>%
  group_by(name) %>%
    summarize(Male = sum(male),
              Female = sum(female))
ABCDEFGHIJ0123456789
name
<chr>
Male
<dbl>
Female
<dbl>
Aaban1070
Aabha035
Aabid100
Aabir50
Aabriella032
Aada05
Aadam2540
Aadan1300
Aadarsh1990
Aaden46535

Now, we want to figure out what fraction of each name is Male or Female. It doesn’t matter which we do here, I’ll do Male. mutate() a new variable I’ll call perc_male for the percent of the name being for Male babies. It takes the summed variables we made before, and takes the fraction that are Male, multiplying by 100 to get percents (which isn’t necessary, but is easy to read).

babynames %>%
  mutate(male = ifelse(sex == "M", n, 0),
         female = ifelse(sex == "F", n, 0)) %>%
  group_by(name) %>%
    summarize(Male = sum(male),
              Female = sum(female))%>%
  mutate(perc_male = (Male/(Male+Female)*100))
ABCDEFGHIJ0123456789
name
<chr>
Male
<dbl>
Female
<dbl>
perc_male
<dbl>
Aaban1070100.00000000
Aabha0350.00000000
Aabid100100.00000000
Aabir50100.00000000
Aabriella0320.00000000
Aada050.00000000
Aadam2540100.00000000
Aadan1300100.00000000
Aadarsh1990100.00000000
Aaden4653599.89265779

Right now, it’s still in alphabetical order. We want to arrange it by perc_male, and more importantly, we want perc_male to be between 48 and 52, so let’s filter accordingly:

babynames %>%
  mutate(male = ifelse(sex == "M", n, 0),
         female = ifelse(sex == "F", n, 0)) %>%
  group_by(name) %>%
    summarize(Male = sum(male),
              Female = sum(female))%>%
  mutate(perc_male = (Male/(Male+Female)*100)) %>%
  arrange(perc_male) %>%
  filter(perc_male > 48,
         perc_male < 52)
ABCDEFGHIJ0123456789
name
<chr>
Male
<dbl>
Female
<dbl>
perc_male
<dbl>
Demetrice1623175448.06041
Shenan252748.07692
Yael3162341448.08394
Harlo16417748.09384
Daylyn20221848.09524
Oluwatosin13915048.09689
Chaning131448.14815
Kirin35137848.14815
Odera131448.14815
Jireh64469348.16754

This gives us a lot of names, all falling between 48% and 52% male. But we want the most popular names that are in this range. So let’s finally mutate a new variable called total that simply adds the number of Male and Female babies with a name. Then let’s arrange our results by desc(total) to get the largest first, and then slice(1:10) to get the top 10 only.

babynames %>%
  mutate(male = ifelse(sex == "M", n, 0),
         female = ifelse(sex == "F", n, 0)) %>%
  group_by(name) %>%
    summarize(Male = sum(male),
              Female = sum(female))%>%
  mutate(perc_male = (Male/(Male+Female)*100)) %>%
  arrange(perc_male) %>%
  filter(perc_male > 48,
         perc_male < 52) %>%
  mutate(total = Male+Female) %>%
  arrange(desc(total)) %>%
  slice(1:10)
ABCDEFGHIJ0123456789
name
<chr>
Male
<dbl>
Female
<dbl>
perc_male
<dbl>
total
<dbl>
Kerry495964853450.5411298130
Robbie208632226448.3757343127
Justice170801578251.9749332862
Blair144701419550.4796828665
Kris139821349050.8954627472
Elisha133301359949.5005426929
Unknown9307941649.7089118723
Mckinley9389895551.1829518344
Baby6078587150.8661811949
Santana4651495248.432789603

Political and Economic Freedom Around the World

For the remaining questions, we’ll look at the relationship between Economic Freedom and Political Freedom in countries around the world today. Our data for economic freedom comes from the Fraser Institute, and our data for political freedom comes from Freedom House.

Question 8

Download these two datasets that I’ve cleaned up a bit:6

Load them with df<-read_csv("name_of_the_file.csv") and save one as econfreedom and the other as polfreedom. Look at each tibble you’ve created.

I am creating this document for/from the website, so these are all stored in a folder called data, one folder up from my current folder, homeworks. To get there, I go up one folder (..) and move to data, where these csv files are stored.

I suggest you either keep the data in the same folder as your R working directory (always check with getwd()), or create an R Project and store the data files in that same folder.

# import data with read_csv from readr

# note these file paths will be different for you
polfreedom<-read_csv("../data/freedomhouse2018.csv")
## Parsed with column specification:
## cols(
##   .default = col_double(),
##   `Country/Territory` = col_character(),
##   Status = col_character()
## )
## See spec(...) for full column specifications.
econfreedom<-read_csv("../data/econfreedom.csv")
## Warning: Missing column names filled in: 'X1' [1]
## Parsed with column specification:
## cols(
##   X1 = col_double(),
##   Country = col_character(),
##   ISO = col_character(),
##   ef = col_double(),
##   gdp = col_double(),
##   continent = col_character()
## )
# look at each dataframe
polfreedom
ABCDEFGHIJ0123456789
Country/Territory
<chr>
Status
<chr>
PR Rating
<dbl>
CL Rating
<dbl>
A1
<dbl>
A2
<dbl>
A3
<dbl>
A
<dbl>
B1
<dbl>
B2
<dbl>
AbkhaziaPF45321623
AfghanistanNF56101222
AlbaniaPF33332834
AlgeriaNF65111311
AndorraF114441244
AngolaNF66021321
Antigua and BarbudaF224441234
ArgentinaF224431143
ArmeniaPF54112422
AustraliaF114441244
econfreedom
ABCDEFGHIJ0123456789
X1
<dbl>
Country
<chr>
ISO
<chr>
ef
<dbl>
gdp
<dbl>
continent
<chr>
1AlbaniaALB7.404543.0880Europe
2AlgeriaDZA5.154784.1943Africa
3AngolaAGO5.084153.1463Africa
4ArgentinaARG4.8110501.6603Americas
5AustraliaAUS7.9354688.4459Oceania
6AustriaAUT7.5647603.7968Europe
7BahrainBHR7.6022347.9708Asia
8BangladeshBGD6.35972.8807Asia
9BelgiumBEL7.5145181.4382Europe
10BeninBEN6.22804.7240Africa

Question 9

The polfreedom dataset is still a bit messy. Let’s overwrite it (or assign to something like polfreedom2) and select Country/Territory and Total (total freedom score) and rename Country.Territory to Country.

polfreedom<-polfreedom %>%
  select(`Country/Territory`, Total) %>%
  rename(Country=`Country/Territory`)

Question 10

Now we can try to merge these two datasets into one. Since they both have Country as a variable, we can merge these tibbles using left_join(econfreedom, polfreedom, by="Country")7 and save this as a new tibble (something like freedom).

This one is a bit advanced to explain (but see the last few slides of 1.5 for more), so just copy what I gave you!

freedom<-left_join(econfreedom, polfreedom, by="Country")

Question 11

Now make a scatterplot of Political Freedom (total)8 as y on Economic Freedom (ef) as x and color by continent.

## Warning: Removed 1 rows containing missing values (geom_point).

Question 12

Let’s do this again, but highlight some key countries. Pick three countries, and make a new tibble from freedom that is only the observations of those countries. Additionally, install and load a packaged called ggrepel9 Next, redo your plot from question 11, but now add a layer: geom_label_repel and set its data to your three-country tibble, use same aesthetics as your overall plot, but be sure to add label = ISO, to use the ISO country code to label.10

# install.packages("ggrepel") install for first use 
library(ggrepel) # load 

interest<-filter(freedom, ISO %in% c("CHN", "NOR", "USA"))

ggplot(data=freedom, aes(x=ef,y=Total))+
  geom_point(aes(color=continent))+
  geom_label_repel(data=interest, aes(ef, Total, label=ISO,color=continent),alpha=0.6)+
  xlab("Economic Freedom Score")+ylab("Political Freedom Score")+theme_bw()+labs(caption="Sources: Frasier Institute, Freedom House")+
  theme_classic(base_family = "Fira Sans Condensed", base_size=16)
## Warning: Removed 1 rows containing missing values (geom_point).

Question 13

Make another plot similar to 12, except this time use GDP per Capita (gdp) as y. Feel free to try to put a regression line with geom_smooth()!11. Those of you in my Development course, you just made my graphs from Lesson 2!

ggplot(data=freedom, aes(x=ef,y=gdp))+
  geom_point(aes(color=continent))+
  geom_smooth(data=freedom)+
  geom_label_repel(data=interest, aes(ef, Total, label=ISO,color=continent),alpha=0.6)+
  xlab("Economic Freedom Score")+ylab("Political Freedom Score")+theme_bw()+labs(caption="Sources: Frasier Institute, Freedom House")+
  theme_classic(base_family = "Fira Sans Condensed", base_size=16)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'


  1. Or percent, if you made that variable, as I did.↩︎

  2. If your name isn’t in there :(, pick a random name.↩︎

  3. Hint: if you do this, you’ll get the number of rows (years) there are in the data. You want to add the number of babies in each row (n), so inside count, add wt=n to weight the count by n.↩︎

  4. Hint: once you’ve got all the right conditions, you’ll get a table with a lot of data. You only want to slice the 1st row for each table.↩︎

  5. This is hard to define. For our purposes, let’s define this as names where between 48 and 52% of the babies with the name are Male.↩︎

  6. If you want, try downloading them from the websites yourself!↩︎

  7. Note, if you saved as something else in question 9., use that instead of polfreedom!↩︎

  8. Feel free to rename these!↩︎

  9. This automatically adjusts labels so they don’t cover points on a plot!↩︎

  10. You might also want to set a low alpha level to make sure the labels don’t obscure other points!↩︎

  11. If you do, be sure to set its data to the full freedom, not just your three countries!↩︎