Pandas是一个Python中用于进行数据分析的库,它可以生成类似Excel表格式的数据表,而且可以对数据进行修改操作。Pandas还有个强大的功能,它可以从很多不同种类的数据库中提取数据,如SQL数据库、Excel表格甚至CSV文件。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
数据帧(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
同样地,对行也可以做相同的操作。
面板(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维。
当任何匹配特定值的数据(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
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文件的处理。
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
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
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
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...
数据清洗是对一些没有用的数据进行处理的过程。很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况,如果要使数据分析更加准确,就需要对这些没有用的数据进行处理。在本节中,将利用Pandas包来进行数据清洗。实例中使用到的测试数据为property-data.csv,可在根文件夹下打开该文件。文件中包含n/a、NA、-、na四种空数据。
如果要删除包含空字段的行,可以使用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-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
数据错误也是很常见的情况,可以对错误的数据进行替换或移除。
【例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
如果要清洗重复数据,可以使用duplicated()和drop_duplicates()方法。如果对应的数据是重复的,duplicated()会返回True,否则返回False。
【例2-54】 清洗重复数据演示。
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