文章目录
- 题目描述
- 源数据集
- 数据分析
题目描述
美国社会保障局(SSA)提供了从1880年至现在的婴儿姓名频率的数据。可以使用这些数据做很多事情:
根据给定的名字对婴儿名字随时间的比例进行可视化
确定一个名字的相对排位
确定每年最受欢迎的名字,或者流行程度最高或最低的名字
源数据集
点此获得该系列1-4数据
提取码:if5a
数据分析
加载其中一个数据集,即1880年出生婴儿名字数据集
names1880 = pd.read_csv("datasets/babynames/yob1880.txt",
names=["name", "sex", "births"])
names1880
先将数据集中按性别作为索引,统计1880年男女出生比例
按年份先后顺序,读取数据集文件,将年份添加成新的索引,将这些数据合并显示
names1880.groupby("sex")["births"].sum()
pieces = []
for year in range(1880, 2011):
path = f"datasets/babynames/yob{year}.txt"
frame = pd.read_csv(path, names=["name", "sex", "births"])
# Add a column for the year
frame["year"] = year
pieces.append(frame)
# Concatenate everything into a single DataFrame
names = pd.concat(pieces, ignore_index=True)
names
将出生的人按年份与性别做成透视表,使用pivot_table()函数创建了一个数据透视表total_births,其中聚合了"births"列,以"year"作为行索引,以"sex"作为列索引,并使用sum函数进行聚合。通过total_births.tail()可以查看数据透视表的最后几行,以了解总出生人数按性别和年份的情况。使用total_births.plot()绘制了一个关于总出生人数按性别和年份的折线图,其中标题为"Total births by sex and year"。
total_births = names.pivot_table("births", index="year",
columns="sex", aggfunc=sum)
total_births.tail()
total_births.plot(title="Total births by sex and year")
定义了一个名为add_prop的函数,用于在groupby操作中添加一个名为"prop"的新列,该列计算每个组内的出生人数占总出生人数的比例。使用groupby函数按照"year"和"sex"两个列进行分组,并将add_prop函数应用于每个分组。参数group_keys=False用于禁止在结果中包含组键。
def add_prop(group):
group["prop"] = group["births"] / group["births"].sum()
return group
names = names.groupby(["year", "sex"], group_keys=False).apply(add_prop)
names
计算每个分组内出生人数占总出生人数的比例的和,验证数据是否有丢失。
names.groupby(["year", "sex"])["prop"].sum()
按照年份与性别分组,取得出生的婴儿所求最多的名字前一千排成列表
def get_top1000(group):
return group.sort_values("births", ascending=False)[:1000]
grouped = names.groupby(["year", "sex"])
top1000 = grouped.apply(get_top1000)
top1000.head()
top1000 = top1000.reset_index(drop=True)
top1000.head()
按照时间排序将以上数据可视化,以名字为索引,每个名字画一张折线图
boys = top1000[top1000["sex"] == "M"]
girls = top1000[top1000["sex"] == "F"]
total_births = top1000.pivot_table("births", index="year",
columns="name",
aggfunc=sum)
total_births.info()
subset = total_births[["John", "Harry", "Mary", "Marilyn"]]
subset.plot(subplots=True, figsize=(12, 10),
title="Number of births per year")
将年份、性别、所占比例做成透视图并作可视化,可以得到这些前1000名取得名字随着时代的变化,这些大众名字概率正在下降。
table = top1000.pivot_table("prop", index="year",
columns="sex", aggfunc=sum)
table.plot(title="Sum of table1000.prop by year and sex",
yticks=np.linspace(0, 1.2, 13))
2010年出生的男孩按取名概率降序排列,并计算累计和,0.5出现在第116个名字,而1900年仅仅出现在24个名字,大众名字确实在减少。下图是1880年到2010年名字概率累计和达到0.5时索引值的变化。
df = boys[boys["year"] == 2010]
df
prop_cumsum = df["prop"].sort_values(ascending=False).cumsum()
prop_cumsum[:10]
prop_cumsum.searchsorted(0.5)
df = boys[boys.year == 1900]
in1900 = df.sort_values("prop", ascending=False).prop.cumsum()
in1900.searchsorted(0.5)
def get_quantile_count(group, q=0.5):
group = group.sort_values("prop", ascending=False)
return group.prop.cumsum().searchsorted(q) + 1
diversity = top1000.groupby(["year", "sex"]).apply(get_quantile_count)
diversity = diversity.unstack()
fig = plt.figure()
diversity.head()
diversity.plot(title="Number of popular names in top 50%")
列举1910,1960,2010三年出生的婴儿名字的最后一个字母的出现次数,并计算其出现的比率可视化。可以看出近些年男婴以n结尾现象占大部分还在急剧增加,女婴以a结尾名字也在逐年增多,以e结尾也占很大一部分,但是在逐年衰减。
def get_last_letter(x):
return x[-1]
last_letters = names["name"].map(get_last_letter)
last_letters.name = "last_letter"
table = names.pivot_table("births", index=last_letters,
columns=["sex", "year"], aggfunc=sum)
subtable = table.reindex(columns=[1910, 1960, 2010], level="year")
subtable.head()
subtable.sum()
letter_prop = subtable / subtable.sum()
letter_prop
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 1, figsize=(10, 8))
letter_prop["M"].plot(kind="bar", rot=0, ax=axes[0], title="Male")
letter_prop["F"].plot(kind="bar", rot=0, ax=axes[1], title="Female",
legend=False)
取得男婴上述数据,摘取"d", “n”, "y"单独进行观察,发现随着时间进行,d与y短暂出现了峰值,然后快速下降;而n却不断攀升
plt.subplots_adjust(hspace=0.25)
letter_prop = table / table.sum()
dny_ts = letter_prop.loc[["d", "n", "y"], "M"].T
dny_ts.head()
plt.close("all")
fig = plt.figure()
dny_ts.plot()
在前一千的表格中找到包含"Lesl"的计算其出现总数与出现比例,,可视化可以得到在男生在这些字符出现频率逐年下降,而女生中增加。
all_names = pd.Series(top1000["name"].unique())
lesley_like = all_names[all_names.str.contains("Lesl")]
lesley_like
filtered = top1000[top1000["name"].isin(lesley_like)]
filtered.groupby("name")["births"].sum()
table = filtered.pivot_table("births", index="year",
columns="sex", aggfunc="sum")
table = table.div(table.sum(axis="columns"), axis="index")
table.tail()
fig = plt.figure()
table.plot(style={"M": "k-", "F": "k--"})