如何在Python中使用Pandas

282 阅读19分钟

如何在Python中使用Pandas

当我们谈论数据科学时,我们通常指的是通过总结、可视化、在数据中学习模式的复杂算法(机器学习)和其他花哨的工具进行数据分析。当我们与软件开发人员讨论这个术语时,我们也会听到很多Python,这种流行的编程语言。

但是,为什么Python在数据科学领域如此流行和特别?有很多原因,其中一个重要的原因是Python生态系统和库,它们使数据科学在Python中显得自然。

其中一个库是pandas,世界上每个数据科学都在使用,使用过,或者至少听说过(如果你是一个从未使用过pandas的数据科学家,请在评论中尖叫)。

Pandas是生态系统的重要组成部分,许多其他的数据科学工具都建立在Pandas之上,或者为Pandas提供特定的功能。

本指南为开发者介绍pandas,旨在涵盖pandas最常用功能的内容、原因和方法。

在我们开始之前,如果你想访问这个项目的完整源代码来跟随,你可以从GitHub下载这个项目的源代码。


Pandas是做什么的?

Pandas,在过去的几年里,已经确立了自己作为数据分析的最佳库之一的地位。正是由于Pandas的重要性和强大的功能,数据科学家在收到数据集时,首先要做的事情就是将其加载到Pandas中开始理解它。

Pandas为他们提供了清理、转换和分析数据所需的一切。它为分析师提供了如此之多的功能,以至于可以把它们做成整本书。

下面是你可以用pandas做的一些事情:

  • 描述:获取数据集的信息,计算统计值,回答诸如平均数、中位数、最小值、最大值、相关性、分布等直接问题。
  • 清理。删除重复的,替换空值,过滤行、列
  • 转换:计算新的数值,重命名列,突变你的数据
  • 视觉化。用matplotlib、seaborn或其他方式直接从你的pandas数据集建立最先进的可视化。
  • 存储:从CSV、JSON等文件加载和保存数据,或者直接连接到数据库

安装和导入

Pandas是一个外部库,因此,需要为你的项目安装。这个库的名字是pandas ,你可以用你最喜欢的Python软件包管理器来安装它。在我的例子中,我使用pipenv ,因为我不是Conda的忠实粉丝,但过程是一样的。

如果你从GitHub上查看了我的代码,只需运行以下命令,因为所有的依赖都在Pipfile上了

pipenv install

如果你想从一个新的项目中继续学习这个教程,你可以简单地通过运行安装pandas。

pipenv install pandas

我强烈建议使用Jupyter笔记本,就像我在数据上进行实验和测试一样,所以你也必须通过运行以下命令来安装它。

pipenv install notebook

如果你需要更多关于如何使用Jupyter笔记本的信息,你可以查看这个指南

开始前的最后一件事是导入库。

import pandas as pd

并非一定要提供别名,但使用pd ,这是很常见的,它让人很直接,而且人们也是这样做的,所以让我们跟着做吧。


Pandas的基础。系列和数据框架

Pandas的所有功能都有两个基本构件:SeriesDataFrames 。简单地说,一个Series 是一个列,而DataFrames 是一个有多个Series 的多维数据集。


读取数据

尽管你可以在pandas中手动创建DataFrames,但它之所以容易使用,是因为它能够直接从CSV、JSON或数据库等多个来源加载数据。

从CSV文件

使用pandas读取CSV文件就像一行代码一样简单。

df_titanic = pd.read_csv("titanic.csv")
df_titanic.head()
乘客身份存活Pclass...票价机舱登船
0103...7.2500S
1211...71.2833C85C
2313...7.9250S
3411...53.1000C123S
4503...8.0500S

导入一个CSV文件很简单,只需用文件名调用一个函数read_csv 。第二行代码调用函数head ,打印出前五行的数据。稍后会有更多的介绍。

从一个JSON文件

读取JSON文件并不比读取CSV文件更复杂,只是一个简单的函数调用问题。

df_json = pd.read_json("sample.json")
df_json.head()
产品价格
0台式电脑900
1平板电脑360
2苹果手机700
3笔记本电脑1460

从SQL数据库中

与读取CSV或JSON文件相比,从SQL数据库中读取数据需要一些额外的步骤。这是因为pandas本身并不支持数据库,而是依靠第三方库来建立连接。

一旦与数据库的连接准备好了,你就可以使用函数read_sql_query ,直接使用pandas工作。

在我们的方案中,我们将从SQLLite读取数据,但也支持其他数据库引擎,如MySQL、Postgres等。

注意:如果你是自己运行这段代码,而不是使用教程提供的项目,在继续之前,请确保你已经安装了pysqlite3

正如所讨论的,首先,我们需要建立一个与数据库的连接。

import sqlite3
con = sqlite3.connect("chinook.db")

之后,我们可以直接在pandas中运行SQL查询来检索信息。如果你需要关于SQL的帮助,我可以推荐Udemy上完整的SQL训练营课程。

在我们的案例中,我们将只从一个表中获取数据。

df_sql = pd.read_sql_query("SELECT * FROM albums", con)
df_sql.head()
AlbumId标题艺术家
01为那些即将摇滚的人,我们向你致敬1
12墙面上的球2
23躁动与狂野2
34摇滚乐1
45大人物3

自定义

到目前为止,我们通过使用默认值来读取数据,在大多数情况下效果很好。然而,可能在某些情况下,你需要改变读取和解析数据的方式。Pandas的读取函数是完整的,并提供了大量的自定义功能。你可以在官方文档中阅读这些内容。

一个重要的和高度使用的参数是index_col ,它允许你指定用作DataFrame索引的一列或几列。这在切分或选择数据时非常有用,我们将在本指南的后面进行。

df_drinks = pd.read_csv("data/drinks.csv", index_col="country")
df_drinks.head()

在Pandas中保存数据

有时我们会对我们的数据集进行修改,以促进数据分析。然而,除非我们保存这些变化,否则这些变化会丢失。Pandas提供了简单的方法来将DataFrame存储到文件或数据库中。

df.to_csv('saved.csv')  
df.to_json('saved.json')  
df.to_sql('saevd, con)

请注意,我们可以将数据存储在任何类型的文件上,不管我们第一次加载的格式是什么。


描述你的数据

当你第一次加载你的数据集时,你想了解它的结构并开始对数据进行理解。在本节中,我们将介绍基本的pandas函数,这些函数将确切地帮助你实现这一目标。

我们要介绍的第一个函数是我们已经介绍过的head 函数。这个函数在屏幕上打印出第一个n 行的数据,它对于首次探索数据集的列和类型是很方便的。

你可以在没有参数的情况下运行这个函数,在这种情况下将默认为5行。

df_titanic.head()

或者你可以传递你想看的行数。

df_titanic.head(10)
PassengerId存活Pclass...票价机舱登船
0103...7.2500S
1211...71.2833C85C
2313...7.9250S
3411...53.1000C123S
4503...8.0500S
5603...8.4583Q
6701...51.8625E46S
7803...21.0750S
8913...11.1333S
91012...30.0708C

如果你想看最后几行,你可以使用函数tail 。和head ,你可以提供你想看的行数。

df_titanic.tail()
乘客身份存活的Pclass...票价机舱登船
88688702...13.0000⊿ΤS
88788811...30.0000B42S
88888903...23.4500⊿ΤS
88989011...30.0000C148C
89089103...7.7500ǞǞǞQ

另一个你可能需要在加载数据后运行的有趣的函数是info ,它提供了关于你的数据集的基本信息,如行和列的数量、非空值的数量、数据类型和内存使用情况。

df_titanic.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

如果你想知道你的数据有多少列和多少行,那么你可以得到DataFrame的shape 属性。

df_titanic.shape

(注意,shape 是一个属性,而不是一个函数)

(891, 12)

如果你想更好地了解你的数据集的值,那么函数describe 将提供每一列的统计摘要,包括计数、平均值、标准差等信息。

df_titanic.describe()
乘客身份存活级别年龄寿命舱位寿命
891.000000891.000000891.000000714.000000891.000000891.000000891.000000
平均值446.0000000.3838382.30864229.6991180.5230080.38159432.204208
标准257.3538420.4865920.83607114.5264971.1027430.80605749.693429
最小值1.0000000.0000001.0000000.4200000.0000000.0000000.000000
25%223.5000000.0000002.00000020.1250000.0000000.0000007.910400
50%446.0000000.0000003.00000028.0000000.0000000.00000014.454200
75%668.5000001.0000003.00000038.0000001.0000000.00000031.000000
最大891.0000001.0000003.00000080.0000008.0000006.000000512.329200

操纵数据框架

数据框架暴露了数以百计的方法来处理数据集,太多了,不可能全部了解。然而,一些操作在数据分析任务中经常出现。我们将回顾所有这些对所有数据科学家来说都是至关重要的方法。

删除重复数据

重复的数据会扭曲我们的结果,所以必须处理它们。Pandas提供了一些处理重复的工具,比如drop_duplicates ,它可以自动从DataFrame中删除所有重复的值。

df_movies = pd.read_csv(‘movies.csv')
df_movies.shape
df_movies = df_movies.drop_duplicates()
df_movies.shape

请注意,在我们的例子中,我们加载了一个包含两个重复值的新文件,下面是结果。

(77, 8)
(75, 8)

请记住,drop_duplicates 不会影响原始的DataFrame(默认情况下),相反,它将返回一个具有唯一值的新DataFrame。你也可以通过参数inplace=True 来修改原始数据。

重命名列

在pandas中,有几种方法可以重命名数据框架的列,但其中最有用和最简单的方法是使用rename 函数。

df_tmp = df_titanic.rename(columns = {"PassengerId" : "PassId"})
df_tmp.head()
PassId存活Pclass...票价机舱登船
0103...7.2500S
1211...71.2833C85C
2313...7.9250S
3411...53.1000C123S
4503...8.0500S

类似于drop_columnrename ,将返回一个带有更新的新的DataFrame。

rename 也支持一次重命名多个列。

df_tmp = df_titanic.rename(columns = {"PassengerId" : "PassId", "Pclass": "PassClass"})
df_tmp.head()
PassId存活通行证类别...票价机舱登船
0103...7.2500S
1211...71.2833C85C
2313...7.9250S
3411...53.1000C123S
4503...8.0500S

处理缺失值的工作

在现实生活中,数据缺失可能是一个大问题。幸运的是,pandas的设计可以检测缺失值或NA(Not Available)值。为了检测空值,我们使用isnull() 函数。

df_titanic.isnull()
PassengerId存活Pclass...车票票价机舱登船
0假的虚假...虚假准确
1...
2...准确
3...
4...准确
..........................
886假的...假的准确
887...虚假
888...虚假准确
889...虚假
890虚假虚假...假的准确假的

isnull 函数返回一个新的DataFrame,其形状与原DataFrame相同,并带有布尔值(True或False),表明某个单元格是否为空。这对于执行计算或替换空值非常有帮助。

有时我们不能处理缺失的值,所以最好是简单地删除整个行。你可以通过函数dropna 来实现。

df_titanic.shape
tmp = df_titanic.dropna()
tmp.shape

其中的结果是。

(891, 12)
(183, 12)

从结果来看,我们的大部分记录至少包含一个空列。在这种情况下,简单地从DataFrame中删除所有这些行并不是明智的做法。

切片、选择、提取数据

到目前为止,我们一直在处理整个数据集或执行基本的过滤,如删除空行。但是我们怎样才能有意地从DataFrames中选择数据呢?

有两种方法可以访问或切分pandas DataFrame,可以按列或按行。

按列

在一个DataFrame上按列提取数据是超级简单的。你只需使用[] ,并注明系列(列)名称,如下所示。

ds_survived = df_titanic['Survived']
ds_survived
type(ds_survived)

在这种情况下,它将输出。

0      0
1      1
2      1
3      1
4      0
      ..
886    0
887    1
888    0
889    1
890    0
Name: Survived, Length: 891, dtype: int64

pandas.core.series.Series

注意,结果是一个DataSeries而不是一个DataFrame。有时因为两者的一些方法和属性不同,我们想把一个DataSeries转换成一个DataFrame,我们通过使用[[]] 符号来实现。

df_survived = df_titanic[['Survived']]
type(df_survived)

其中输出:

pandas.core.frame.DataFrame

按行当按行选择数据时,我们有比按列选择更多的选择。我们可以通过索引访问某一行,或者通过查询或应用条件反射在数据集中进行搜索。

我们将从属性loc 开始,允许通过标签或一个布尔数组访问一组行和列。

请注意,如果我们尝试使用loc 与标签,你需要对你的DataFrame进行索引,就像我们在上面的饮料DataFrame的情况一样。

df_drinks.loc['Argentina']

此外,你需要考虑到按索引查找需要精确匹配,而且是区分大小写的,所以在我们的例子中,Argentina 是正确的,但Argargentina 会引起异常。

该代码的输出结果是

beer_servings                   193
spirit_servings                  25
wine_servings                   221
total_litres_of_pure_alcohol    8.3
continent                        SA
Name: Argentina, dtype: object

有趣的是,你也可以使用我们对列表所做的相同技术同时访问多条记录,因此,例如

df_drinks.loc['Argentina': 'Austria']

这将返回一个新的DataFrame,其中包括ArgentinaAustria 之间的所有结果。

国家啤酒供应量酒类供应量葡萄酒饮用量纯酒精的总升数大陆
阿根廷193252218.3SA
亚美尼亚21179113.8欧盟
澳大利亚2617221210.4喀麦隆
奥地利279751919.7欧盟

如何过滤没有标签的数据?你可以使用索引的属性iloc ,这相当于在Python的列表上进行切片。

df_drinks.iloc[6:10]

这将产生与上面相同的结果,从索引6 (阿根廷)直到索引10-1 (奥地利)进行选择。

也可以指定一个增量,就像我们对列表所做的一样。

df_drinks.iloc[6:10:2]

有时你需要只显示符合某些条件的行,比如显示啤酒份数超过320的国家。为此,你可以使用条件选择。

下面是这个例子的代码。

df_drinks.loc[df_drinks['beer_servings'] > 320]

让我们把它分解一下。df_drinks['beer_servings'] > 320 是一个特殊的条件,因为它适用于一个完整的DataSeries。其结果将是一个新的DataSeries,其布尔值代表原始DataFrame中每一行的条件结果。

然后,通过使用布尔型DataSeries的df_drinks[] ,我们返回一个新的DataFrame,过滤掉所有在条件型DataSeries上有False值的行。

除了委内瑞拉和纳米比亚的情况,我对结果并不感到太惊讶。

国家啤酒供应量酒类供应量葡萄酒饮用量纯酒精的总升数大陆
捷克共和国36117013411.8欧盟
加蓬34798598.9AF
德国34611717511.3欧盟
立陶宛3432445612.9欧盟
纳米比亚376316.8AF
波兰3432155610.9欧盟
委内瑞拉33310037.7SA

注意:在其他一些教程中,你可能会发现同样的代码,但把.loc ,例如

df_drinks[df_drinks['beer_servings'] > 320]

虽然在这种情况下,这段代码是有效的,但有一个角落的情况,它不会,所以显性比隐性好,使用.loc 。你可以在StackOverflow的这个线程中阅读更多关于这方面的内容。


统计学

统计学和数学是数据科学家应该掌握的最重要的技能之一。幸运的是,pandas让我们可以很容易地对我们的数据集进行统计计算。

聚合统计

本节将介绍如何对数据集进行一些统计计算,如均值、groupby和计数函数。

首先使用mean() ,该函数将返回数值型DataSeries的平均值。

df_drinks.mean()

-------------------------
Output
-------------------------
beer_servings                   106.160622
spirit_servings                  80.994819
wine_servings                    49.450777
total_litres_of_pure_alcohol      4.717098
dtype: float64

mean() 函数只返回了数字列的均值,这很有意义,因为你不能对文本进行统计计算。

我们也可以在DataSeries层面上进行这种计算,在这种情况下,我们将返回一个单一的计算数字。

df_drinks["beer_servings"].mean()

-------------------------
Output
-------------------------
106.16062176165804

比方说,你想根据一个特定的组来计算一些列的平均值,所以为了这个目标,你必须使用一个名为groupby() 的pandas函数。

df_drinks.groupby("continent")["beer_servings"].mean()

-------------------------
Output
-------------------------
continent
AF     61.471698
AS     37.045455
EU    193.777778
OC     89.687500
SA    175.083333
Name: beer_servings, dtype: float64

通过使用groupby ,我们可以执行按数据集分组的计算,例如各大洲的平均值。

平均值一样,你可以计算中位数最小值最大值总和等等。

另一个流行的功能是计算行/列的数量,这可以通过使用count

df.count(axis = 0)

-------------------------
Output
-------------------------
beer_servings                   193
spirit_servings                 193
wine_servings                   193
total_litres_of_pure_alcohol    193
continent                       170
dtype: int64

通过指定axis=0(默认值),我们计算每列的行数。然而,我们也可以反转轴(axis=1),计算每行的列数。

df.count(axis = 1)

-------------------------
Output
-------------------------
country
Afghanistan    5
Albania        5
Algeria        5
Andorra        5
Angola         5
              ..
Venezuela      5
Vietnam        5
Yemen          5
Zambia         5
Zimbabwe       5
Length: 193, dtype: int64

常用函数

本节将讨论pandas中一些最常见的统计函数,这是任何数据科学家的武器库中必须具备的。

让我们从cov函数开始,它将计算列的成对协方差。请看下面的代码

df_drinks.cov()
beer_servings烈酒葡萄酒饮用量纯酒精的总升数
啤酒供应量10229.9271914096.9539624249.458468318.992031
酒类服务4096.9539627794.1197651370.601306218.184985
葡萄酒_服务4249.4584681370.6013066351.707200200.762044
纯酒精的总公升数318.992031218.184985200.76204414.237779

cov 函数已经计算出所有列的成对协方差值。

另一个常用的计算数值变化百分比的pandas函数是pct_change 。这个函数将计算出当前值与前一个元素相比的变化百分比。

ind = pd.date_range('01/01/2020', periods = 7, freq ='W')    
df_tmp = pd.DataFrame({"A":[4, 14, 3, 6, 2, 55, 33], 
                   "B":[5, 2, 54, 34, 2, 32, 56],  
                   "C":[20, 20, 17, 31, 8, 5, 3], 
                   "D":[14, 3, 6, 2, 3, 4, 12]}, index = ind)
df_tmp.pct_change()
ABCD
2020-01-05
2020-01-122.500000-0.6000000.000000-0.785714
2020-01-19-0.78571426.000000-0.1500001.000000
2020-01-261.000000-0.3703700.823529-0.666667
2020-02-02-0.666667-0.941176-0.7419350.500000
2020-02-0926.50000015.000000-0.3750000.333333
2020-02-16-0.4000000.750000-0.4000002.000000

首先,我们使用date_range() 函数创建了一个数据系列索引,并创建了一个只包含随机值的数据框作为示范,最后对该数据应用了百分比变化函数。

现在让我们看看如何计算两个数值的关系,也就是所谓的相关关系。使用的函数叫corr() ,它计算你的数据框架中所有列的关系,不包括空值、不可用的值和非数字数据,如文本。

df_tmp = pd.DataFrame({"A":[6, 8, 3, 4],  
                   "B":[51, 2, 6, 3], 
                   "C":[7, 2, 9, 5], 
                   "D":[5, 4, 4, 22]})
df_tmp.corr()
ABCD
A1.0000000.167894-0.792908-0.369624
B0.1678941.0000000.345789-0.300948
C-0.7929080.3457891.000000-0.154586
D-0.369624-0.300948-0.1545861.000000

我们已经使用了前面的协方差例子的随机值来计算列的相关性。

学习如何根据特定的标准对你的数据进行排名,比如根据电影的评级分数对电影数据集进行排名,这是数据科学中处理数据集时最常用的东西之一。下面的例子将使用Pandas中的rank函数。

df_movies['revenue_rank'] = df_movies["Worldwide Gross"].rank()
df_movies.head()

我们创建了一个名为"'revenue_rank'"的新列,该列由rank 函数根据 "全球总收入 "分配的排名。

绘图

Pandas本身不能绘图,但它提供了帮助方法,将使用绘图引擎,如matplotlibseaborn 来执行该任务。

对于我们的指南,我们将使用matplotlib,如果你自己运行代码,请确保你已经安装了该库。如果你使用的是GitHub上的代码,这已经是一个项目依赖。

散点图

散点图是显示基于两个变量的点的图,幸运的是,Pandas让我们很容易通过一个简单的函数plot() ,就可以创建一个散点图。

colors = df_titanic["Survived"].replace(1, 'green').replace(0, 'red')
df_titanic.plot(x='Fare', y="Age", c=colors, colormap="Reds", kind="scatter")

线形图

线形图是用一条线连接的一系列数值,它是最常用的图表之一。Pandas也能够非常容易地显示这种图表。请看下面的代码。

df_titanic.loc[df_titanic["Survived"] == 1].groupby("Age")['Survived'].count().plot()

条形图

条形图是数据可视化领域中最常见的图表之一,基本上是用矩形条表示分类数据。Pandas也提供这种图表。请看下面的代码。

df_titanic["Survived"].value_counts().plot(kind="bar")

直方图:

df_titanic.hist(bins=10,figsize=(9,7),grid=False)

或者更复杂的图表。这里有一篇关于为这个特定数据集构建图表的有趣文章。


结论

数据科学家在进入可视化过程之前,首先需要探索、清理和转换他们的数据。Pandas只需一些简单的命令就能轻松完成这些操作,并且可以用来绘制数据,而不是使用其他库,如matplotlib和seaborn。不过,你可能会发现自己需要学习这些可视化库来绘制更复杂的图表。

谢谢你的阅读!