介绍
Python pandas
包用于数据操作和分析,旨在让您以直观的方式处理标记或关系数据。
pandas
包提供了电子表格功能,但由于您使用的是 Python,它比传统的图形电子表格程序更快、更高效。
在本教程中,我们将介绍如何设置要使用的大型数据集、pandas
的 groupby()
和 pivot_table()
函数,以及如何可视化数据。
要熟悉 pandas
包,您可以阅读我们的教程 An Introduction to the pandas Package and its Data Structures in Python 3。
先决条件
本指南将介绍如何在本地桌面或远程服务器上处理 pandas
中的数据。 处理大型数据集可能会占用大量内存,因此无论哪种情况,计算机都需要至少 2GB 内存 来执行本指南中的一些计算。
在本教程中,我们将使用 Jupyter Notebook 来处理数据。 如果您还没有它,您应该按照我们的 教程安装和设置适用于 Python 3 的 Jupyter Notebook。
设置数据
在本教程中,我们将使用来自 Social Security 网站 的美国社会保障数据,该数据以 8MB zip 文件的形式提供。
让我们在我们的 本地机器 或我们的 服务器 上从正确的目录激活我们的 Python 3 编程环境:
cd environments
. my_env/bin/activate
现在让我们为我们的项目创建一个新目录。 我们可以称它为 names
然后进入目录:
mkdir names cd names
在此目录中,我们可以使用 curl
命令从社会保障网站提取 zip 文件:
curl -O https://www.ssa.gov/oact/babynames/names.zip
下载文件后,让我们验证我们是否已安装将要使用的所有软件包:
numpy
支持多维数组matplotlib
可视化数据pandas
用于我们的数据分析seaborn
让我们的 matplotlib 统计图形更美观
如果您还没有安装任何软件包,请使用 pip
安装它们,如下所示:
pip install pandas pip install matplotlib pip install seaborn
如果您还没有 numpy
软件包,也将安装它。
现在我们可以启动 Jupyter Notebook:
jupyter notebook
进入 Jupyter Notebook 的 Web 界面后,您将在那里看到 names.zip
文件。
要创建新的笔记本文件,请从右上角的下拉菜单中选择 New > Python 3:
这将打开一个笔记本。
让我们从 导入 我们将要使用的包开始。 在我们的笔记本顶部,我们应该写下以下内容:
import numpy as np import matplotlib.pyplot as pp import pandas as pd import seaborn
我们可以通过键入 ALT + ENTER
来运行此代码并移动到新的代码块。
让我们也告诉 Python Notebook 保持我们的图表内联:
matplotlib inline
让我们运行代码并继续键入 ALT + ENTER
。
从这里开始,我们将继续解压缩 zip 存档,将 CSV 数据集加载到 pandas
,然后连接 pandas
DataFrames。
解压缩 Zip 存档
要将 zip 存档解压缩到当前目录,我们将导入 zipfile
模块,然后使用文件名调用 ZipFile
函数(在我们的例子中为 names.zip
) :
import zipfile zipfile.ZipFile('names.zip').extractall('.')
我们可以运行代码并通过键入 ALT + ENTER
继续。
现在,如果您回头查看 names
目录,您将拥有 CSV 格式的名称数据的 .txt
文件。 这些文件将与 1881 年至 2015 年的存档数据年份相对应。 这些文件中的每一个都遵循类似的命名约定。 例如,2015 文件称为 yob2015.txt
,而 1927 文件称为 yob1927.txt
。
要查看其中一个文件的格式,让我们使用 Python 打开一个并显示前 5 行:
open('yob2015.txt','r').readlines()[:5]
运行代码并继续 ALT + ENTER
。
Output['Emma,F,20355\n', 'Olivia,F,19553\n', 'Sophia,F,17327\n', 'Ava,F,16286\n', 'Isabella,F,15504\n']
数据格式的方式是姓名优先(如 Emma
或 Olivia
),性别其次(如 F
用于女性姓名,M
用于男性名字),然后是当年以该名字出生的婴儿数量(2015 年出生的名为 Emma 的婴儿有 20,355 名)。
有了这些信息,我们就可以将数据加载到 pandas
中。
将 CSV 数据加载到 pandas
要将逗号分隔值数据加载到 pandas
中,我们将使用 pd.read_csv()
函数,传递文本文件的名称以及我们决定的列名。 我们将其分配给一个变量,在本例中为 names2015
,因为我们使用的是 2015 年出生文件中的数据。
names2015 = pd.read_csv('yob2015.txt', names = ['Name', 'Sex', 'Babies'])
键入 ALT + ENTER
以运行代码并继续。
为了确保这成功了,让我们显示表格的顶部:
names2015.head()
当我们运行代码并继续 ALT + ENTER
时,我们将看到如下所示的输出:
我们的表格现在包含按列组织的每个名字的出生婴儿的姓名、性别和数量的信息。
连接 pandas
对象
连接 pandas
对象将允许我们处理 names
目录中所有单独的文本文件。
要连接这些,我们首先需要通过将变量分配给未填充的 列表数据类型 来初始化列表:
all_years = []
完成后,我们将使用 for 循环 按年份迭代所有文件,范围从 1880 年到 2015 年。 我们将 +1
添加到 2015 的末尾,以便将 2015 包含在循环中。
all_years = [] for year in range(1880, 2015+1):
在循环中,我们将使用 字符串格式化程序 将每个文本文件值附加到列表中来处理每个文件的不同名称。 我们将这些值传递给 year
变量。 同样,我们将为 Name
、Sex
和 Babies
的数量指定列:
all_years = [] for year in range(1880, 2015+1): all_years.append(pd.read_csv('yob{}.txt'.format(year), names = ['Name', 'Sex', 'Babies']))
此外,我们将为每一年创建一个列以保持这些列。 我们可以在每次迭代后使用 -1
的索引在循环进行时指向它们。
all_years = [] for year in range(1880, 2015+1): all_years.append(pd.read_csv('yob{}.txt'.format(year), names = ['Name', 'Sex', 'Babies'])) all_years[-1]['Year'] = year
最后,我们将使用 pd.concat()
函数将其添加到 pandas
对象中。 我们将使用变量 all_names
来存储此信息。
all_years = [] for year in range(1880, 2015+1): all_years.append(pd.read_csv('yob{}.txt'.format(year), names = ['Name', 'Sex', 'Babies'])) all_years[-1]['Year'] = year all_names = pd.concat(all_years)
我们现在可以使用 ALT + ENTER
运行循环,然后通过调用结果表的尾部(最底部的行)来检查输出:
all_names.tail()
我们的数据集现在已经完成,可以在 pandas
中使用它进行额外的工作。
分组数据
使用 pandas
,您可以使用 .groupby()
功能按列对数据进行分组。 将我们的 all_names
变量用于我们的完整数据集,我们可以使用 groupby()
将数据拆分到不同的桶中。
让我们按性别和年份对数据集进行分组。 我们可以这样设置:
group_name = all_names.groupby(['Sex', 'Year'])
我们可以运行代码并继续 ALT + ENTER
。
此时,如果我们只调用 group_name
变量,我们将得到以下输出:
Output<pandas.core.groupby.DataFrameGroupBy object at 0x1187b82e8>
这向我们表明它是一个 DataFrameGroupBy
对象。 这个对象有关于如何对数据进行分组的说明,但它没有给出关于如何显示值的说明。
要显示值,我们需要给出说明。 例如,我们可以计算 .size()
、.mean()
和 .sum()
来返回一个表。
让我们从 .size()
开始:
group_name.size()
当我们运行代码并继续 ALT + ENTER
时,我们的输出将如下所示:
OutputSex Year F 1880 942 1881 938 1882 1028 1883 1054 1884 1172 ...
这些数据看起来不错,但它可能更具可读性。 我们可以通过附加 .unstack
函数使其更具可读性:
group_name.size().unstack()
现在,当我们运行代码并继续键入 ALT + ENTER
时,输出如下所示:
这些数据告诉我们的是每年有多少女性和男性名字。 例如,在 1889 年,有 1,479 个女性名字和 1,111 个男性名字。 2015年有18,993个女性名字和13,959个男性名字。 这表明随着时间的推移,名称的多样性更大。
如果我们想得到出生婴儿的总数,我们可以使用.sum()
函数。 让我们将其应用于较小的数据集,即我们之前创建的单个 yob2015.txt
文件中的 names2015
集:
names2015.groupby(['Sex']).sum()
让我们输入 ALT + ENTER
来运行代码并继续:
这向我们展示了 2015 年出生的男性和女性婴儿的总数,尽管数据集中只计算了该年名字被使用至少 5 次的婴儿。
pandas
.groupby()
函数允许我们将数据分割成有意义的组。
数据透视表
数据透视表对于汇总数据很有用。 他们可以自动对存储在一张表中的数据进行排序、计数、总计或平均。 然后,他们可以在汇总数据的新表格中显示这些操作的结果。
在 pandas
中,pivot_table()
函数用于创建数据透视表。
要构建数据透视表,我们将首先调用要使用的 DataFrame,然后调用要显示的数据以及它们的分组方式。
在此示例中,我们将使用 all_names
数据,并在一个维度显示按名称分组的婴儿数据,在另一个维度显示按年份分组:
pd.pivot_table(all_names, 'Babies', 'Name', 'Year')
当我们键入 ALT + ENTER
运行代码并继续时,我们将看到以下输出:
因为这显示了很多空值,我们可能希望将 Name 和 Year 保留为列,而不是一种情况下的行和另一种情况下的列。 我们可以通过将数据分组在方括号中来做到这一点:
pd.pivot_table(all_names, 'Babies', ['Name', 'Year'])
一旦我们输入 ALT + ENTER
来运行代码并继续,这个表现在将只显示每个名称记录的年份数据:
OutputName Year Aaban 2007 5.0 2009 6.0 2010 9.0 2011 11.0 2012 11.0 2013 14.0 2014 16.0 2015 15.0 Aabha 2011 7.0 2012 5.0 2014 9.0 2015 7.0 Aabid 2003 5.0 Aabriella 2008 5.0 2014 5.0 2015 5.0
此外,我们可以对数据进行分组,将姓名和性别作为一个维度,将年份作为另一个维度,如下所示:
pd.pivot_table(all_names, 'Babies', ['Name', 'Sex'], 'Year')
当我们运行代码并继续 ALT + ENTER
时,我们将看到下表:
数据透视表让我们可以从现有表中创建新表,从而决定我们希望如何对数据进行分组。
可视化数据
通过将 pandas
与 matplotlib
等其他包一起使用,我们可以在笔记本中可视化数据。
多年来,我们将可视化有关给定名称流行度的数据。 为了做到这一点,我们需要设置和排序索引来重新处理数据,这将使我们能够看到特定名称的流行度变化。
pandas
包允许我们执行分层或多级索引,这使我们能够存储和操作具有任意数量维度的数据。
我们将使用性别信息索引我们的数据,然后是姓名,然后是年份。 我们还需要对索引进行排序:
all_names_index = all_names.set_index(['Sex','Name','Year']).sort_index()
输入 ALT + ENTER
运行并继续我们的下一行,我们将让 notebook 显示新的索引 DataFrame:
all_names_index
运行代码并继续 ALT + ENTER
,输出将如下所示:
接下来,我们将要编写一个函数来绘制一个名称随时间的流行度。 我们将调用函数 name_plot
并传递 sex
和 name
作为我们将在运行函数时调用的参数。
def name_plot(sex, name):
我们现在将设置一个名为 data
的变量来保存我们创建的表。 我们还将使用 pandas
DataFrame loc
来通过索引值选择我们的行。 在我们的例子中,我们希望 loc
基于 MultiIndex 中的字段组合,同时引用 sex
和 name
数据。
让我们把这个结构写到我们的函数中:
def name_plot(sex, name): data = all_names_index.loc[sex, name]
最后,我们要使用我们导入为 pp
的 matplotlib.pyplot
绘制值。 然后,我们将根据索引绘制性别和姓名数据的值,我们的目的是年。
def name_plot(sex, name): data = all_names_index.loc[sex, name] pp.plot(data.index, data.values)
键入 ALT + ENTER
运行并移动到下一个单元格。 我们现在可以使用我们选择的性别和姓名来调用该函数,例如 F
表示女性姓名,其名称为 Danica
。
name_plot('F', 'Danica')
当您现在键入 ALT + ENTER
时,您将收到以下输出:
请注意,根据您使用的系统,您可能会收到有关字体替换的警告,但数据仍会正确绘制。
从可视化中可以看出,女性名字 Danica 在 1990 年左右有小幅上升,并在 2010 年之前达到顶峰。
我们创建的函数可用于绘制来自多个名称的数据,以便我们可以看到不同名称随时间变化的趋势。
让我们先让我们的情节更大一点:
pp.figure(figsize = (18, 8))
接下来,让我们创建一个包含我们想要绘制的所有名称的列表:
pp.figure(figsize = (18, 8)) names = ['Sammy', 'Jesse', 'Drew', 'Jamie']
现在,我们可以使用 for
循环遍历列表并绘制每个名称的数据。 首先,我们将尝试将这些中性名称作为女性名称:
pp.figure(figsize = (18, 8)) names = ['Sammy', 'Jesse', 'Drew', 'Jamie'] for name in names: name_plot('F', name)
为了使这些数据更容易理解,让我们添加一个图例:
pp.figure(figsize = (18, 8)) names = ['Sammy', 'Jesse', 'Drew', 'Jamie'] for name in names: name_plot('F', name) pp.legend(names)
我们将键入 ALT + ENTER
以运行代码并继续,然后我们将收到以下输出:
虽然每个名字都作为女性名字慢慢流行起来,但杰米这个名字在 1980 年左右作为女性名字压倒性地流行。
让我们绘制相同的名字,但这次是男性名字:
pp.figure(figsize = (18, 8)) names = ['Sammy', 'Jesse', 'Drew', 'Jamie'] for name in names: name_plot('M', name) pp.legend(names)
再次键入 ALT + ENTER
以运行代码并继续。 该图将如下所示:
该数据显示出更受欢迎的名字,Jesse 通常是最受欢迎的选择,并且在 1980 年代和 1990 年代特别受欢迎。
从这里,您可以继续使用名称数据,创建关于不同名称及其受欢迎程度的可视化,并创建其他脚本来查看不同的数据以进行可视化。
结论
本教程向您介绍了处理大型数据集的方法,包括设置数据、使用 groupby()
和 pivot_table()
对数据进行分组、使用 MultiIndex 索引数据以及可视化 [ X203X] 数据使用 matplotlib
包。
许多组织和机构提供数据集,您可以使用这些数据集继续了解 pandas
和数据可视化。 例如,美国政府通过 data.gov 提供数据。
您可以按照我们的指南了解有关使用 matplotlib
可视化数据的更多信息 如何使用 matplotlib 在 Python 3 中绘制数据和 如何使用 matplotlib 和 Python 3[X205X 绘制词频图表]。