购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.3 Pandas库

Pandas是一个Python中用于进行数据分析的库,它可以生成类似Excel表格式的数据表,而且可以对数据进行修改操作。Pandas还有个强大的功能,它可以从很多不同种类的数据库中提取数据,如SQL数据库、Excel表格甚至CSV文件。Pandas还支持在不同的列中使用不同类型的数据,如整型数、浮点数,或是字符串。

2.3.1 Pandas系列

系列(Series)是能够保存任何类型的数据(整数、字符串、浮点数、Python对象等)的一维标记数组。轴标签统称为索引。

Series由索引(index)和列组成,函数如下。

     pandas.Series(data,index,dtype,name,copy)

其中,data为一组数据(ndarray类型);index为数据索引标签,如果不指定,默认从0开始;dtype为数据类型,默认会自己判断;name为设置名称;copy表示是否复制数据,默认为False。

【例2-43】 利用各种方法创建系列。

     #创建一个基本系列是一个空系列
     import pandas as pd
     s=pd.Series()
     print(s)
     Series([],dtype:float64)
     #从ndarray创建一个系列
     import numpy as np
     data=np.array(['a','b','c','d'])
     s=pd.Series(data)
     print(s)
     0  a
     1  b
     2  c
     3  d
     dtype:object
     #从字典创建一个系列
     data={'a':0.,'b':1.,'c':2.}
     s=pd.Series(data)
     print(s)
     a  0.0
     b  1.0
     c  2.0
     dtype:float64
     #从标量创建一个系列
     s=pd.Series(5,index=[0,1,2,3])
     print(s)
     0  5
     1  5
     2  5
     3  5
     dtype:int64

如果只需要字典中的一部分数据,则指定需要数据的索引即可。

     import pandas as pd
     sites={1:"Google",2:"Python",3:"Hello"}
     myvar=pd.Series(sites,index=[1,2])
     print(myvar)
     1   Google
     2   Python
     dtype:object
     
     #设置Series名称参数
     sites={1:"Google",2:"Python",3:"Hello"}
     myvar=pd.Series(sites,index=[1,2],name="PYTHON-Series-TEST")
     print(myvar)
     1   Google
     2   Python
     Name:PYTHON-Series-TEST,dtype:object

2.3.2 Pandas数据结构

数据帧(DataFrame)是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(如数值、字符串、布尔型值)。DataFrame既有行索引也有列索引,它可以被看作由Series组成的字典(共同用一个索引),如图2-11所示。

Pandas中的DataFrame可以使用以下构造函数创建:

     pandas.DataFrame(data,index,columns,dtype,copy)

data为一组数据(如ndarray、series、map、lists、dict等类型);index为索引值,或者可以称为行标签;columns为列标签,默认为RangeIndex(0,1,2,…,n);dtype为数据类型;copy表示是否复制数据,默认为False。

图2-11 DataFrame数据结构

【例2-44】 利用各种方法创建DataFrame。

     #创建一个空的DataFrame
     import pandas as pd
     df=pd.DataFrame()
     print(df)
     Empty DataFrame
     Columns:[]
     Index:[]
     
     #从列表创建DataFrame
     data=[['Alex',10],['Bob',12],['Clarke',13]]
     df=pd.DataFrame(data,columns=['Name','Age'])
     print(df)
          Name Age
     0  Alex 10
     1  Bob   12
     2 Clarke 13
     
     #从ndarrays/Lists的字典来创建DataFrame
     data={'Name':['Tom','Jack','Steve','Ricky'],'Age':[28,34,29,42]}
     df=pd.DataFrame(data)
     print(df)
        Age Name
     0 28  Tom
     1 34   Jack
     2 29 Steve
     3 42 Ricky
     
     #如何使用字典、行索引和列索引列表创建数据帧(DataFrame)
     data=[{'a':1,'b':2},{'a':5,'b':10,'c':20}]
     #具有两个列索引,值与字典键相同
     df1=pd.DataFrame(data,index=['first','second'],columns=['a','b'])
     #具有两个列索引,其中一个索引具有其他名称
     df2=pd.DataFrame(data,index=['first','second'],columns=['a','b1'])
     print(df1)
     print(df2)
             a b
     first  1 2
     second 5 10
             a b1
     first  1   NaN
     second 5   NaN

在Pandas中可以对列进行选择、添加、删除操作等。

【例2-45】 对列进行操作。

     #从数据帧(DataFrame)中选择一列
     import pandas as pd
     d={'one':pd.Series([1,2,3],index=['a','b','c']),
             'two':pd.Series([1,2,3,4],index=['a','b','c','d'])}
     df=pd.DataFrame(d)
     print(df['one'])
             a b
     first   1   2
     second  5   10
             a   b1
     first   1   NaN
     second  5   NaN
     
     #向现有数据框添加一个新列
     d={'one':pd.Series([1,2,3],index=['a','b','c']),
             'two':pd.Series([1,2,3,4],index=['a','b','c','d'])}
     df=pd.DataFrame(d)
     #通过传递新序列将新列添加到具有列标签的现有DataFrame对象
     print("通过作为系列传递添加新列:")
     df['three']=pd.Series([10,20,30],index=['a','b','c'])
     print(df)
     print("使用DataFrame中的现有列添加新列:")
     df['four']=df['one']+df['three']
     print(df)

通过作为系列传递添加新列:

        one  two three
     a  1.0     1    10.0
     b  2.0     2    20.0
     c  3.0     3    30.0
     d  NaN     4    NaN

使用DataFrame中的现有列添加新列:

        one  two  three  four
     a  1.0     1      10.0      11.0
     b  2.0     2      20.0      22.0
     c  3.0     3      30.0      33.0
     d  NaN     4      NaN       NaN

同样地,对行也可以做相同的操作。

2.3.3 Pandas面板

面板(Panel)是3D容器的数据,3轴(axis)这个名称旨在给出描述涉及面板数据的操作的一些语义,分别如下。

items-axis 0:每个项目对应于内部包含的数据帧(DataFrame)。

major_axis-axis 1:它是每个数据帧(DataFrame)的索引(行)。

minor_axis-axis 2:它是每个数据帧(DataFrame)的列。

可以使用以下构造函数创建面板。

     pandas.Panel(data,items,major_axis,minor_axis,dtype,copy)

其中,data为数据采取各种形式和另一个数据帧;items为axis=0;major_axis为axis=1;minor_axis为axis=2;dtype为每列的数据类型;copy表示是否复制数据,默认为False。

在SciPy中,可以使用多种方式创建面板。

(1)从ndarrays创建。

(2)从DataFrames的dict创建。

【例2-46】 用不同方式创建面板。

     #从3D ndarray创建
     #创建一个空面板
     import pandas as pd
     import numpy as np
     data=np.random.rand(2,4,5)
     p=pd.Panel(data)
     print(p)
     <class  'pandas.core.panel.Panel'>
     Dimensions:2(items)x 4(major_axis)x 5(minor_axis)
     Items axis:0 to 1
     Major_axis axis:0 to 3
     Minor_axis axis:0 to 4

注意: 观察空面板和上面板的尺寸大小,所有对象都不同。

     #从DataFrame对象的dict创建面板
     data={'Item1':pd.DataFrame(np.random.randn(4,3)),
                'Item2':pd.DataFrame(np.random.randn(4,2))}
     p=pd.Panel(data)
     print(p)
     <class  'pandas.core.panel.Panel'>
     Dimensions:2(items)x 4(major_axis)x 3(minor_axis)
     Items axis:Item1 to Item2
     Major_axis axis:0 to 3
     Minor_axis axis:0 to 2

如果要从面板中选择数据,可以使用Items、Major_axis、Minor_axis这3种方式。

【例2-47】 从面板中选择数据。

     #使用Items
     import pandas as pd
     import numpy as np
     data={'Item1':pd.DataFrame(np.random.randn(4,3)),
                'Item2':pd.DataFrame(np.random.randn(4,2))}
     p=pd.Panel(data)
     print(p['Item1'])
             0     1    2
     0-0.076656-0.522665-0.990586
     1-1.181011-0.994811 0.370761
     2-1.755909 0.981063-1.126204
     3 2.276633   0.015866 0.273384

上面代码中有两个数据项,这里只检索Item1。结果是具有4行和3列的数据帧(DataFrame),它们是Major_axis维和Minor_axis维。

2.3.4 Pandas稀疏数据

当任何匹配特定值的数据(NaN/缺失值,尽管可以选择任何值)被省略时,稀疏对象被“压缩”。即SparseIndex对象跟踪数据被“稀疏”。在Pandas中,所有的标准数据结构都应用了to_sparse()方法。

【例2-48】 利用to_sparse()方法创建稀疏对象。

     import pandas as pd
     import numpy as np
     ts=pd.Series(np.random.randn(8))
     ts[2:-2]=np.nan
     sts=ts.to_sparse()
     print(sts)
     0  1.706639
     1    1.036985
     2    NaN
     3    NaN
     4    NaN
     5    NaN
     6 -1.091275
     7    1.027179
     dtype:float64
     BlockIndex
     Block locations:array([0,6])
     Block lengths:array([2,2])

由于内存效率的原因,所以需要稀疏对象的存在。例如,假设有一个很大的NA DataFrame,执行下面的代码:

     df=pd.DataFrame(np.random.randn(10000,4))
     df.ix[:9998]=np.nan
     sdf=df.to_sparse()
     print(sdf.density)
     0.0001

通过调用to_dense()可以将任何稀疏对象转换回标准密集形式。

     ts=pd.Series(np.random.randn(10))
     ts[2:-2]=np.nan
     sts=ts.to_sparse()
     print(sts.to_dense())
     0  1.386588
     1    1.171640
     2    NaN
     3    NaN
     4    NaN
     5    NaN
     6    NaN
     7    NaN
     8 -2.712764
     9    1.473722
     dtype:float64

稀疏数据应该具有与其密集表示相同的dtype。目前,支持float64、int64和booldtypes。

     s=pd.Series([1,np.nan,np.nan])
     print(s)
     print("\n")
     s.to_sparse()
     print(s)
     0  1.0
     1    NaN
     2    NaN
     dtype:float64
     
     0    1.0
     1    NaN
     2    NaN
     dtype:float64

2.3.5 Pandas CSV文件

CSV(Comma-Separated Values,逗号分隔值,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。CSV是一种通用的、相对简单的文件格式。Pandas可以很方便地处理CSV文件。例如:

     import pandas as pd
     df=pd.read_csv('nba.csv')
     print(df.to_string())

to_string()用于返回DataFrame类型的数据,如果不使用该函数,则输出结果为数据的前面30行和末尾30行,中间部分以…代替。

     import pandas as pd
     df=pd.read_csv('nba.csv')
     print(df)

运行程序,效果如图2-12所示。

图2-12 显示部分结果

也可以使用to_csv()方法将DataFrame类型的数据存储为CSV文件。

     import pandas as pd
     #三个字段name,site,age
     nme=["Taobao","Python","Meituan","SO"]
     st=["www.taobao","www.python.org","www.meituan.com","www.so.com"]
     ag=[92,44,83,98]
     #字典
     dict={'name':nme,'site':st,'age':ag}
     df=pd.DataFrame(dict)
     #保存dataframe
     df.to_csv('site.csv')

运行程序,打开根目录下的site.csv,效果如图2-13所示。

图2-13 site.csv文件

在Python中,提供了相关函数用于实现CSV文件的处理。

1.head函数

head(n)方法用于读取前面的n行,如果不填参数n,默认返回5行。

【例2-49】 利用head()函数读取前几行数据。

     #读取前面5行
     import pandas as pd
     df=pd.read_csv('nba.csv')
     print(df.head())
             Name      Team    Number Position Age Height Weight \
     0   Avery Bradley Boston Celtics      0.0     PG 25.0     6-2     180.0
     1   Jae Crowder  Boston Celtics      99.0    SF 25.0     6-6     235.0
     2   John Holland  Boston Celtics      30.0    SG 27.0     6-5     205.0
     3   R.J.Hunter  Boston Celtics       28.0    SG 22.0     6-5     185.0
     4   Jonas Jerebko Boston Celtics      8.0     PF 29.0     6-10    231.0
     
                 College    Salary
     0   Texas                 7730337.0
     1   Marquette            6796117.0
     2   Boston University     NaN
     3   Georgia State         1148640.0
     4   NaN                   5000000.0
     
     #读取前面8行
     df=pd.read_csv('nba.csv')
     print(df.head(8))
             Name       Team    Number Position  Age Height Weight\
     0   Avery Bradley       Boston Celtics   0.0      PG 25.0        6-2     180.0
     1   Jae Crowder         Boston Celtics   99.0     S 25.0         6-6     235.0
     2   John Holland        Boston Celtics   30.0     SG 27.0        6-5     205.0
     3   R.J.Hunter          Boston Celtics   28.0     SG 22.0        6-5     185.0
     4   Jonas Jerebko       Boston Celtics   8.0      PF 29.0        6-10    231.0
     5   Amir Johnson        Boston Celtics   90.0     PF 29.0        6-9     240.0
     6   Jordan Mickey       Boston Celtics   55.0     PF 21.0        6-8     235.0
     7   Kelly Olynyk        Boston Celtics   41.0      C 25.0        7-0     238.0
     
              College    Salary
     0   Texas               7730337.0
     1   Marquette          6796117.0
     2   Boston University   NaN
     3   Georgia State       1148640.0
     4   NaN                 5000000.0
     5   NaN                 12000000.0
     6   LSU                 1170960.0
     7   Gonzaga             2165160.0
2.tail()函数

tail(n)方法用于读取尾部的n行,如果不填参数n,默认返回5行,空行各个字段的值返回NaN。

【例2-50】 利用tail()函数显示数据的末尾几行。

     #读取末尾5行
     import pandas as pd
     df=pd.read_csv('nba.csv')
     print(df.tail())
                  Name   Team  Number Position Age Height Weight College \
     453   Shelvin Mack   Utah Jazz   8.0             PG 26.0    6-3  203.0      Butler
     454   Raul Neto      Utah Jazz   25.0            PG 24.0    6-1  179.0      NaN
     455   Tibor Pleiss   Utah Jazz   21.0            C  26.0    7-3  256.0      NaN
     456   Jeff Withey    Utah Jazz   24.0            C  26.0    7-0  231.0      Kansas
     457   NaN            NaN         NaN             NaN NaN    NaN    NaN       NaN
     
             Salary
     453   2433333.0
     454   900000.0
     455   2900000.0
     456   947276.0
     457   NaN
     
     #读取末尾7行
     df=pd.read_csv('nba.csv')
     print(df.tail(8))
                  Name    Team  Number Position Age Height Weight College \
     450   Joe Ingles        Utah Jazz       2.0         SF 28.0    6-8     226.0    NaN
     451   Chris Johnson     Utah Jazz       23.0        SF 26.0    6-6     206.0    Dayton
     452   Trey Lyles        Utah Jazz       41.0        PF 20.0    6-10    234.0    Kentucky
     453   Shelvin Mack      Utah Jazz       8.0         PG 26.0    6-3     203.0    Butler
     454   Raul Neto         Utah Jazz       25.0        PG 24.0    6-1     179.0    NaN
     455   Tibor Pleiss      Utah Jazz       21.0        C  26.0    7-3     256.0    NaN
     456   Jeff Withey       Utah Jazz       24.0        C  26.0    7-0     231.0    Kansas
     457   NaN               NaN             NaN         NaN NaN    NaN      NaN      NaN
     
             Salary
     450   2050000.0
     451   981348.0
     452   2239800.0
     453   2433333.0
     454   900000.0
     455   2900000.0
     456   947276.0
     457   NaN
3.info()函数

info()方法返回表格的一些基本信息。

【例2-51】 利用info()函数返回表格的信息。

     import pandas as pd
     df=pd.read_csv('nba.csv')
     print(df.info())

运行程序,输出如下。

     <class 'pandas.core.frame.DataFrame'>
     RangeIndex:458 entries,0 to 457      #行数,458行,第一行编号为0
     Data columns(total 9 columns):                 #列数,9列
     Name        457 non-null object               #non-null意为非空的数据
     Team        457 non-null object
     Number      457 non-null float64
     Position    457 non-null object
     Age         457 non-null float64
     Height      457 non-null object
     Weight     457 non-null float64
     College     373 non-null object
     Salary      446 non-null float64
     dtypes:float64(4),object(5)
     memory usage:32.3+KB
     None

2.3.6 Pandas JSON

JSON(JavaScript Object Notation, JavaScript对象表示法)是存储和交换文本信息的语法,类似XML。JSON比XML更小,更快,更易解析,Pandas可以很方便地处理JSON数据。例如:

     import pandas as pd
     df=pd.read_json('sites.json')
     print(df.to_string())

to_string()用于返回DataFrame类型的数据,也可以直接处理JSON字符串。

运行程序,输出如下。

        id   likes  name     url
     0  A001     61       Python教程     www.python.org
     1  A002     124      meituan        www.meituan.com
     2  A003     45       淘宝           www.taobao.com

JSON对象与Python字典具有相同的格式,所以可以直接将Python字典转换为DataFrame数据,例如:

     import pandas as pd
     #字典格式的JSON
     s={
           "col1":{"column1":1,"column2":2,"column3":3},
           "col2":{"column1":"x","column2":"y","column3":"z"}
     }
     #读取JSON转换为DataFrame
     df=pd.DataFrame(s)
     print(df)

运行程序,输出如下。

              col1  col2
     column1    1       x
     column2    2       y
     column3    3       z

此外,还可以从URL中读取JOSN数据,例如:

     import pandas as pd
     URL= 'https://static.runoob.com/download/sites.json'
     df=pd.read_json(URL)
     print(df)

运行程序,输出如下。

        id  likes   name     url
     0  A001   61       菜鸟教程     www.runoob.com
     1  A002   124      Google       www.google.com
     2  A003   45       淘宝         www.taobao.com

假设有一组内嵌的JSON数据文件nested_list.json,使用以下代码格式化完整内容。

     import pandas as pd
     df=pd.read_json('nested_list.json')
     print(df)

运行程序,输出如下。

         class    school_name\
     0   Year 1    ABC primary school
     1   Year 1    ABC primary school
     2   Year 1    ABC primary school
     
                                                     students
     0 {'id':'A001','name':'Tom','math':60,'phy...
     1 {'id':'A002','name':'James','math':89,'p...
     2 {'id':'A003','name':'Jenny','math':79,'p...

2.3.7 Pandas数据清洗

数据清洗是对一些没有用的数据进行处理的过程。很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况,如果要使数据分析更加准确,就需要对这些没有用的数据进行处理。在本节中,将利用Pandas包来进行数据清洗。实例中使用到的测试数据为property-data.csv,可在根文件夹下打开该文件。文件中包含n/a、NA、-、na四种空数据。

1.Pandas清洗空值

如果要删除包含空字段的行,可以使用dropna()方法,语法格式如下。

     DataFrame.dropna(axis=0,how='any',thresh=None,subset=None,inplace=False)

其中,各参数含义如下。

· axis:默认为0,表示逢空值剔除整行。如果设置参数axis=1,表示逢空值去掉整列。

· how:默认为'any',表示如果一行(或一列)里任何一个数据出现NA就去掉整行(或列)。如果设置how='all',表示一行(或列)都是NA时才去掉这整行(或列)。

· thresh:设置需要多少非空值的数据才可以保留下来。

· subset:设置想要检查的列。如果是多个列,可以使用列名的list作为参数。

· inplace:如果设置为True,将计算得到的值直接覆盖之前的值并返回None,修改的是源数据。

首先,可以通过isnull()判断各个单元格是否为空。

     import pandas as pd
     df=pd.read_csv('property-data.csv')
     print(df['NUM_BEDROOMS'])
     print(df['NUM_BEDROOMS'].isnull())
     0   3
     1   3
     2  n/a      #不当作空值
     3   1
     4   3
     5  NaN              #当作空值
     6   2
     7   1
     8  na               #不当作空值
     Name:NUM_BEDROOMS,dtype:object
     0  False
     1  False
     2  False
     3  False
     4  False
     5  True             #把第6个数据NaN当作空格
     6  False
     7  False
     8  False
     Name:NUM_BEDROOMS,dtype:bool

从以上结果看到,Pandas把NaN当作空数据,N/A和NA不是空数据,不符合要求,因此,需要指定空数据类型,例如:

     missing_values=["n/a","na","--"]
     df=pd.read_csv('property-data.csv',na_values=missing_values)
     print(df['NUM_BEDROOMS'])
     print(df['NUM_BEDROOMS'].isnull())
     0  3.0
     1  3.0
     2  NaN      #当作空值
     3  1.0
     4  3.0
     5  NaN              #当作空值
     6  2.0
     7  1.0
     8  NaN              #当作空值
     Name:NUM_BEDROOMS,dtype:float64
     0  False
     1  False
     2   True            #第3条为空值
     3  False
     4  False
     5   True            #第6条为空值
     6  False
     7  False
     8   True            #第9条为空值
     Name:NUM_BEDROOMS,dtype:bool

接下来的代码演示了利用dropna()方法删除包含空数据的行。

提示:默认情况下,dropna()方法返回一个新的DataFrame,不会修改源数据。如果要修改源数据DataFrame,可以使用inplace=True参数,例如:

     f=pd.read_csv('property-data.csv')
     df.dropna(inplace=True)
     print(df.to_string())

也可以移除指定列有空值的行,例如:

也可以使用fillna()方法来替换一些空字段,例如:

还可以指定某一个列来替换数据,例如:

Pandas使用mean()、median()和mode()方法计算列的均值(所有值加起来的平均值)、中位数值(排序后排在中间的数)和众数(出现频率最高的数)。

其他两个函数的用法与mean()函数一致。

2.Pandas清洗格式错误数据

数据格式错误的单元格会使数据分析变得困难,甚至不可能。可以通过包含空单元格的行,或者将列中的所有单元格转换为相同格式的数据。

【例2-52】 自动纠正格式日期。

     import pandas as pd
     #第三个日期格式错误
     data={
       "Date":['2022/10/01','2022/10/02','20221016'],
       "duration":[50,40,45]
     }
     df=pd.DataFrame(data,index=["day1","day2","day3"])
     df['Date']=pd.to_datetime(df['Date'])
     print(df.to_string())

运行程序,输出如下。

            Date     duration
     day1 2022-10-01       50
     day2 2022-10-02       40
     day3 2022-10-16       45
3.Pandas清洗错误数据

数据错误也是很常见的情况,可以对错误的数据进行替换或移除。

【例2-53】 清洗错误数据演示。

     #替换错误年龄的数据
     import pandas as pd
     person={
       "name":['Google','Python','Taobao'],
       "age":[52,15,12345]          #年龄数据12345是错误的
     }
     df=pd.DataFrame(person)
     df.loc[2,'age']=32                             #修改数据
     print(df.to_string())
        age  name
     0  52      Google
     1  15      Python
     2  32      Taobao
     #也可以设置条件语句
     person={
       "name":['Google','Python','Taobao'],
       "age":[52,160,12345]
     }
     df=pd.DataFrame(person)
     for x in df.index:
       if df.loc[x,"age"]>110:
          df.loc[x,"age"]=110
     print(df.to_string())
        age    name
     0  52       Google
     1  110      Python
     2  110      Taobao
     
     #也可以将错误数据的行删除
     person={
       "name":['Google','Python','Taobao'],
       "age":[50,30,12345]              #年龄数据12345是错误的
     }
     df=pd.DataFrame(person)
     for x in df.index:
       if df.loc[x,"age"]>100:
          df.drop(x,inplace=True)
     print(df.to_string())
        age    name
     0  50       Google
     1  30       Python
4.Pandas清洗重复数据

如果要清洗重复数据,可以使用duplicated()和drop_duplicates()方法。如果对应的数据是重复的,duplicated()会返回True,否则返回False。

【例2-54】 清洗重复数据演示。 JWA26AWHLg01NAIrwY8mYt07V/bG60KXGWYRvoqFLIe+G40Dbu5U8Sr5M9lrD0d/

     import pandas as pd
     person={
       "name":['Google','Python','Taobao','Taobao'],
       "age":[50,20,23,23]
     }
     df=pd.DataFrame(person)
     print(df.duplicated())
     0  False
     1  False
     2  False
     3    True
     dtype:bool
     #删除重复数据,可以直接使用drop_duplicates()方法
     df=pd.DataFrame(persons)
     df.drop_duplicates(inplace=True)
     print(df)
        age    name
     0  50       Google
     1  20       Python
     2  23       Taobao
点击中间区域
呼出菜单
上一章
目录
下一章
×