pandas的数据结构
Series
-
Series是一种类似于一维数组的对象,它由一组数据(各种NumPy数据类型)以及一组与之相关的数据标签(即索引)组成。
-
输出时:索引在左边,值在右边,如果没有指定索引,则自动创建0-N-1的整数型索引,可以通过series的value和index获取数组的表示形式和索引对象
-
添加索引:在index参数中添加与数组同长度的数组,对各个数据点进行标记
-
使用索引进行选取series的单个值或一组值
-
obj2['a'] # 单个值 obj2[['a','b','c']] # 一组值
-
-
使用NumPy函数或类似NumPy的运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等)都会保留索引值的链接
-
obj2[obj2 > 0] obj2 * 2 np.exp(obj2)
-
-
可以将series看成定长的有序字典,可以将其看成索引值到数据值的映射,可以用在许多原本需要字典参数的函数
-
# 使用字典创建series sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} obj3 = pd.Series(sdata)
-
如果只传入一个字典,则结果Series中的索引就是原字典的键(有序排列)。你可以传入排好序的字典的键以改变顺序:
-
states = ['California', 'Ohio', 'Oregon', 'Texas'] obj4 = pd.Series(sdata, index=states)
-
如果传入的index在是sdata中没有找到对应的值,则其结果的值就会为NAN(表示缺失或NA值),如果sdata中有值,而索引未传入,则直接从结果中抹除
-
-
pandas的
isnull
和notnull
函数可用于检测缺失数据-
pd.isnull(obj4) pd.notnull(obj4)
-
-
series中最重要的一个功能:能根据运算的索引标签自动对齐数字,类似于数据库的join方法
-
series对象本身与其索引都有一个name属性
-
series的索引可以通过赋值的方式就地修改,必须修改全部的索引,不能部分修改
-
obj = pd.Series([4,7,-5,3],index=range(4)) # 0 4 # 1 7 # 2 -5 # 3 3 # dtype: int64 obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan'] # 正确的 # Bob 4 # Steve 7 # Jeff -5 # Ryan 3 # dtype: int64 obj.index[0] = 1 # 错误的
-
Dataframe
-
DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。
-
建DataFrame:
-
直接传入一个有等长列表或NumPy数组组成的字典
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]} frame = pd.DataFrame(data)
-
使用嵌套字典:
-
如果使用嵌套字典,则pandas会被解释为:外层的键作为列,内层的键作为行索引
-
-
其他:
-
-
head方法:
-
# head方法会选取前5行数据 frame.head()
-
-
建立DataFrame时,如果传入列序列,在DataFrame的列就会按照指定顺序进行排列
-
pd.DataFrame(data, columns=['year', 'state', 'pop'])
-
如果传入的列在数据中找不到,则会在结果中产生缺失值
-
-
通过类似字典标记的方式或属性的方式,可以将DataFrame的列获取为一个Series
-
列也可以通过复制的方式进行修改
-
frame2['debt'] = 16.5
-
-
当使用列表或数组进行赋值给某列时,其长度必须与DataFrame的长度相匹配,如果赋值的是Series,则会精确匹配DataFrame的索引。如果为不存在的列赋值则会创建出一个新列,注:不能用frame.eastern创建新的列
-
del方法可以用来删除这列
-
使用类似NumPy数组的方法,对DataFrame进行转置
frame.T
-
如果设置的DataFrame的index和columns的name属性,则这些信息会被显示出来
-
与series一样,value属性会以二维ndarry的形式返回DataFrame中的数据
-
如果DataFrame各列的数据类型不同,则值数组的的type会选用能兼容所有列的数据类型
索引对象
-
pandas的索引对象负者管理轴标签和其他元数据,构建Series和DataFrame时,所用到的任何数组或其他序列的标签都会被换成一个Index
-
Index对象是不可变的,因此用户不能对其进行修改
-
不可变可以使Index对象在多个数据结构之间安全共享
-
除了类似于数组,index也类似于一个固定大小的集合,但与Python不同的是,pandas的index可以包含重复的标签,选择重复的标签,会显示所有结果
基本功能
重新索引
-
reindex()
根据新索引进行重排,如果某个索引值当前不存在,就引入缺失值-
method='ffill'
实现前项值填充
-
-
借助DataFrame,reindex可以修改(行)索引和列。只传递一个序列时,会重新索引结果的行,重新索引列时,用columns关键字重新索引
丢弃指定轴上的项
-
丢弃某条轴上的一个或多个项很简单,只要有一个索引数组或列表即可。由于需要执行一些数据整理和集合逻辑,所以drop方法返回的是一个在指定轴上删除了指定值的新对象
-
对于DataFrame,可以删除任意轴上的索引值,不指定轴,则默认删除行标签(axis=0),要删除列的值,则传递
axis=1或axis=columns
-
可以就地修改对象,传入
inplace=True
-
小心使用inplace,它会销毁所有被删除的数据
-
索引、选取和过滤
-
Series索引的工作方式类似于Numpy数组的索引,只不过Series索引值不只是整数
-
obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd']) obj['b'] obj[1] obj[2:4] obj[['b', 'a', 'd']] obj[[1, 3]] obj[obj < 2]
-
-
切片运算与Python切片不同,使用标签进行切片其末端是包含的
obj['b':'c]
是包含c的,使用索引切片是不包含末端的obj[0:3]
,使用用切片可以对Series的相应部分进行设置 -
用一个值或序列对DataFrame进行索引其实就是获取一个或多个列
-
索引方式有几个特殊情况,首先通过切片或布尔型数组选取数据
-
data[:2] data[data['three'] > 5]
-
使用loc和iloc进行选取
-
引入特殊的标签运算符loc和iloc,使用轴标签(loc)和整数索引(iloc)从DataFrame选择行和列的子集
-
data.loc['Colorado', ['two', 'three']]
-
data.iloc[2, [3, 0, 1]]
-
整数索引
-
对于整数索引与Python内置的列表和元组的索引语法不同
-
ser = pd.Series(np.arange(3.)) ser ser[-1] # error
-
如果是非整数索引
-
ser2 = pd.Series(np.arange(3.), index=['a', 'b', 'c']) ser2[-1] # 2.0
-
如果轴索引含有整数,数据选取总会使用标签。为了更准确,请使用loc(标签)或iloc(整数)
-
算术运算和数据对齐
-
pandas最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。对于有数据库经验的用户,这就像在索引标签上进行自动外连接
-
自动的数据对齐操作在不重叠的索引处引入了NA值。缺失值会在算术运算过程中传播。对于DataFrame,对齐操作会同时发生在行和列上,其索引和列是原来两个DataFrame的并集
在算术方法中填充值
-
使用算术运算,在没有重叠的位置会产生NA值,而使用填充值,避免NA值
-
In [165]: df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), .....: columns=list('abcd')) In [166]: df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), .....: columns=list('abcde')) In [167]: df2.loc[1, 'b'] = np.nan In [168]: df1 Out[168]: a b c d 0 0.0 1.0 2.0 3.0 1 4.0 5.0 6.0 7.0 2 8.0 9.0 10.0 11.0 In [169]: df2 Out[169]: a b c d e 0 0.0 1.0 2.0 3.0 4.0 1 5.0 NaN 7.0 8.0 9.0 2 10.0 11.0 12.0 13.0 14.0 3 15.0 16.0 17.0 18.0 19.0 # 使用算术运算会出现NA值 In [170]: df1 + df2 Out[170]: a b c d e 0 0.0 2.0 4.0 6.0 NaN 1 9.0 NaN 13.0 15.0 NaN 2 18.0 20.0 22.0 24.0 NaN 3 NaN NaN NaN NaN NaN # 进行填充,避免出现NA值 In [171]: df1.add(df2, fill_value=0) Out[171]: a b c d e 0 0.0 2.0 4.0 6.0 4.0 1 9.0 5.0 13.0 15.0 9.0 2 18.0 20.0 22.0 24.0 14.0 3 15.0 16.0 17.0 18.0 19.0
-
-
在Series和DataFrame中,都有一个副本,以字母r开头,他会翻转参数,
-
1/df1
等价于df1.rdiv(1))
-
DataFrame和Series之间的运算
-
DataFrame和Series之间会进行广播运算
-
默认情况下,DataFrame和Series之间的算术运算会将Series的索引匹配到DataFrame的列,然后沿着行一直向下广播
-
如果某个索引值在DataFrame的列或Series的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集
-
在列上广播,则必须使用算术运算方法
-
frame.sub(series3, axis='index')
-
函数应用和映射
-
NumPy的ufuncs(元素级数组方法)也可用于操作pandas对象
-
frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'),index=['Utah', 'Ohio', 'Texas', 'Oregon']) np.abs(frame)
-
-
将函数应用到由各列或行所形成的一维数组上
-
f = lambda x: x.max() - x.min() frame.apply(f)# 在每列中执行一次, frame.apply(f,axis='columns')# 在每行中执行一次
-
传递到apply的函数不是必须返回一个标量,还可以返回由多个值组成的Series
-
-
将函数应用到元素
-
applymap()
将函数应用到元素上format = lambda x: '%.2f' % x frame.applymap(format)
-
排序和排名
-
使用sort_index方法,返回一个已排序的新对象
-
对于Series,使用sort_index可以根据index排序
-
对于DataFrame,使用sort_index可以根据传入参数(axis)来对任意轴的索引进行排序
-
数据默认是升序,但也可以是降序排列
ascending=False
-
若要按值进行排序,
sort_values
, -
任何缺失值都会默认放到Series末尾,当排序DataFrame时,根据一个或多个列中的值进行排序,那就将一个或多个值的名字传递给sort_values中的by选项,多个值时,先对前一个排序,若其中有相等的,再根据第二个值排序
-
rank方法:默认情况下,rank是通过“为各组分配一个平均排名”的方式破坏平级关系的
-
默认使用
average
,即有相同排名时,取其排名的平均值 -
min
对于相等的值,取较小的排名 -
max
对于相等的值,取较大的排名 -
first
对于相等的值,取最先出现的排名 -
dense
类似于 ”min“,但排名不会出现大于 1 的空隙
-
带有重复标签的轴索引
-
索引的is_unique属性,用来判断它的值是否唯一
-
如果索引对应多个值,则会返回一个Series,而对应单个的值,则返回一个标量值,
汇总和计算描述统计
-
NA值会自动被排除,除非整个切片(这里指的是行或列)都是NA,通过skipna选项可以禁用该功能
相关系数和协方差
-
Series的corr方法用于计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数。与此类似,cov用于计算协方差
-
DataFrame的corr和cov方法将以DataFrame的形式分别返回完整的相关系数或协方差矩阵
-
DataFrame的corrwith方法,计算其列或行跟另一个Series或DataFrame之间的相关系数。传入一个Series将会返回一个相关系数值Series(针对各列进行计算)
唯一性、值计数以及成员资格
-
unique
得到Series中唯一值数组 -
value_counts
用于计算一个Series中各值出现的频率,可用于任何数组或序列 -
isin
判断矢量化集合的成员资格,可用于过滤Series中或DataFrame列中数据的子 -
index.get_indexer
与isin类似的是Index.get_indexer方法,它可以给你一个索引数组,从可能包含重复值的数组到另一个不同值的数组
pandas数据加载、存储与文件格式
读取文本格式的数据
-
函数选项的大致分类
-
索引:将一个或多个列当做返回的DataFrame处理,以及是否从文件、用户获取列名。
-
类型推断和数据转换:包括用户定义值的转换、和自定义的缺失值标记列表等。
-
日期解析:包括组合功能,比如将分散在多个列中的日期时间信息组合成结果中的单个列。
-
迭代:支持对大文件进行逐块迭代。
-
不规整数据问题:跳过一些行、页脚、注释或其他一些不重要的东西(比如由成千上万个逗号隔开的数值数据)。
-
-
sep='分隔符'
指定分隔符 -
header=None
让pandas为其分配默认的列名-
可以自己定义列名
name=['a', 'b', 'c', 'd', 'message']
-
如果希望message列作为索引,可以明确表示要将该列放到索引4的位置上,也可以通过index_col参数指定"message"
-
-
做一个层次化索引,传入由列编号,或列名组成的列表即可
-
parsed = pd.read_csv('examples/csv_mindex.csv',index_col=['key1', 'key2'])
-
-
传入正则表达式作为分隔符
-
result = pd.read_table('examples/ex3.txt', sep='\s+')
-
-
跳过文件的某些行
-
pd.read_csv('examples/ex4.csv', skiprows=[0, 2, 3])
跳过文件的第一、三、四行
-
-
对某些值进行标记,将其标记为NA值
-
使用列表或集合的字符串表示缺失值
-
result = pd.read_csv('examples/ex5.csv', na_values=['NULL']) # 将NULL值标记为NA值
-
字典的各列可以使用不同的NA标记值
-
sentinels = {'message': ['foo', 'NA'], 'something': ['two']}
-
逐块获取文本文件
-
看大文件之前,将pandas显示的更急一些
-
显示10行数据
-
pd.options.display.max_rows = 10
-
只读取几行数据
-
pd.read_csv('examples/ex6.csv', nrows=5)
-
-
逐块读取文件【通过指定chunksize】
-
chunker = pd.read_csv('ch06/ex6.csv', chunksize=1000)
-
返回TextParser对象,可以进行迭代
-
tot = pd.Series([]) for piece in chunker: tot = tot.add(piece['key'].value_counts(), fill_value=0)
-
将数据写入到文本格式中
-
利用DataFrame的
to_csv
方法将数据写到一个以逗号分隔的文件中-
sep='字符串'
可以指定其他分隔符 -
缺失值会被标记为空字符串,也可以标记为其他的标记值
na_rep="NULL"
使用na_rep将缺失值标记为NULL -
如果没有设置其他选项,会写出行和列的标签,也可以进行禁用
index=False,header=False
-
也可以只写出部分列
data.to_csv(sys.stdout, index=False, columns=['a', 'b', 'c'])
不写入索引,并且只写入列为a,b,c,并且按写入的顺序排列
-
-
Series也有
to_csv
方法
处理分隔符格式
-
对于任何单字符分隔符文件,直接使用Python内置的CSV模块,将任意已打开的文件或文件型对象传给csv.reader,对reader进行迭代会为每行产生一个元组,并移除了所有引号
JSON数据
-
已经成为通过HTTP请求在Web浏览器和其他应用程序之间发送数据的标准格式之一。它是一种比表格型文本格式(如CSV)灵活得多的数据格式。
-
json.loads(obj)
实现将JSON字符串转换为Python形式 -
json.dumps(obj)
实现将Python对象转化为JSON格式 -
pandas.read_json
可以自动将特别的JSON数据集转化为Series或DataFrame -
to_json
方法:将数据从pandas输出到JSON
二进制数据格式
-
实现数据的高效二进制格式存储最简单的办法之一是使用Python内置的pickle序列化
-
pandas对象都有一个用于将数据以pickle格式保存到磁盘上的to_pickle方法
-
frame.to_pickle('examples/frame_pickle')
-
-
可以通过pickle直接读取被pickle化的数据,或是使用更为方便的pandas.read_pickle
-
pd.read_pickle('examples/frame_pickle')
-
读取Microsoft Excel文件
-
pandas的ExcelFile类或pandas.read_excel函数支持读取存储在Excel 2003(或更高版本)中的表格型数据。这两个工具分别使用扩展包xlrd和openpyxl读取XLS和XLSX文件。你可以用pip或conda安装它们
-
要使用ExcelFile,通过传递xls或xlsx路径创建一个实例
-
xlsx = pd.ExcelFile('examples/ex1.xlsx')
-
-
使用
read_excel
读取到DataFrame中-
pd.read_excel(xlsx, 'Sheet1')
-
-
将pandas数据写入为Excel格式
-
首先创建一个ExcelWriter,然后使用pandas对象的
to_excel
方法将数据写入其中 -
writer = pd.ExcelWriter('examples/ex2.xlsx') frame.to_excel(writer, 'Sheet1') writer.save()
-
也可以不使用ExcelWriter,而是直接传递文件的路径到
to_excel
-
frame.to_excel('examples/ex2.xlsx')
-
数据清洗和准备
处理缺失数据
-
pandas使用浮点值NaN表示缺失数据
-
Python内置的None值在对象数组中也可以作为NA值
滤除缺失数据
-
对于series
-
可以通过pandas.isnull或布尔索引的手工方法
-
dropna
会更实用一些,并且返回一个含非空数据和索引值的Series-
data.dropna() # 等价于 data[data.notnull()]
-
-
-
-
对于DataFrame
-
dropna()
默认丢弃任何含有缺失值的行 -
指定
axis=1
丢弃任何含有缺失值的列 -
how='all'
只丢弃那些全为NA的行或列 -
thesh=2
保留至少2行,留下一部分观测数据
-
填充缺失值
-
fillna()
方法通过一个常数调用fillna将缺失值替换为常数-
通过调用fillna()
可以实现对不同的列填充不同的值 -
fillna
会返回新对象,但也可以对现有对象进行就地修改 -
对
reindexing
有效的插值方法也可用于fillna()
-
df.fillna(method='ffill')
# 向前填充 -
df.fillna(method='ffill', limit=2)
向前填充,限制为2
-
-
数据转换
移除重复数据
-
DataFrame的
duplicated()
返回一个布尔型Series,表示各行是否是重复的行(前面出现过的行)-
data.duplicated()
-
drop_duplicates()
返回一个一个DataFrame,重复的数组会标为False -
默认判断全部列,可以指定部分列进行重复项判断
data.drop_duplicates(['k1'])
根据k1列过滤重复项 -
默认保存的是第一次出现的值组合,传入
keep='last'
则保留最后一个
-
利用函数或映射进行数据转换
-
map()
函数 -
Series的
str.lower()
将各个值转换为小写 -
data['animal'] = lowercased.map(meat_to_animal)
animal是新建的列,meat_to_animal是不同肉类到动物的映射 -
也可以传入函数
-
data['food'].map(lambda x: meat_to_animal[x.lower()])
-
替换值
-
利用replace
来产生一个新的Series(除非传入inplace=True)-
data.replace(-999, np.nan)
-
将-999替换为NaN
-
如果需要一次性替换多个值,传入一个待替换组成的列表以及一个替换值
-
data.replace([-999, -1000], np.nan)
-
如果要每个值的替换值都不一样则传入一个替换列表
-
data.replace([-999, -1000], [np.nan,0])
-
也可以传入字典
-
data.replace({-999: np.nan, -1000: 0})
-
重命名轴索引
-
跟Series中的值一样,轴标签也可以通过函数或映射进行转换,从而得到一个新的不同标签的对象。轴还可以被就地修改,而无需新建一个数据结构
-
data.index.map()
-
将其传给data.index可以实现就地修改
-
data.index = data.index.map()
-
-
想要创建数据集的转换版(而不是修改原始数据)比较实用的是
rename()
-
可以结合字典型对象实现对部分轴标签的更新
-
-
rename可以实现复制DataFrame并对其索引和列标签进行赋值。如果希望就地修改某个数据集,传入inplace=True即可
-
data.rename(index={'OHIO': 'INDIANA'}, inplace=True)
将OHIO修改为INDIANA
-
离散化和面元划分
-
使用
cut()
将数据划分-
bins = [18, 25, 35, 60, 100] cats = pd.cut(ages, bins)
-
pandas返回的是一个特殊的Categorical对象
-
codes属性中的年龄数据的标签
-
cats.codes # array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
-
-
pd.value_counts(cats)是pandas.cut结果的面元计数。
-
跟“区间”的数学符号一样,圆括号表示开端,而方括号则表示闭端(包括)。哪边是闭端可以通过right=False进行修改
-
可 以通过传递一个列表或数组到labels,设置自己的面元名称
-
group_names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior'] pd.cut(ages, bins, labels=group_names)
-
-
如果向cut传入的是面元的数量而不是确切的面元边界,则它会根据数据的最小值和最大值计算等长面元
-
data = np.random.rand(20) pd.cut(data, 4, precision=2) # [(0.34, 0.55], (0.34, 0.55], (0.76, 0.97], (0.76, 0.97], (0.34, 0.55], ..., (0.34, 0.55], (0.34, 0.55], (0.55, 0.76], (0.34, 0.55], (0.12, 0.34]] # Length: 20 # Categories (4, interval[float64]): [(0.12, 0.34] < (0.34, 0.55] < (0.55, 0.76] < (0.76, 0.97]]
-
precision=2限制小数只有两位
-
-
-
使用
qcut()
-
根据样本分位数对数据进行面元划分
-
cut可能无法使各个面元中含有相同数量的数据点。而qcut由于使用的是样本分位数,因此可以得到大小基本相等的面元
-
检测和过滤异常值
-
选出全部含有“超过3或-3的值”的行,你可以在布尔型DataFrame中使用any方法
-
data[(np.abs(data) > 3).any(1)]
显示data中行有绝对值大于3的行 -
data[(np.abs(data) > 3).any(1)]
对值进行设置,将值限制在-3到3之间
-
排列和随机采样
-
利用numpy.random.permutation函数可以轻松实现对Series或DataFrame的列的排列工作(permuting,随机重排序)
-
然后就可以在基于iloc的索引操作或take函数中使用该数组了
-
df = pd.DataFrame(np.arange(5 * 4).reshape((5, 4))) # 创建数组 sampler = np.random.permutation(5) # 创建随机数组 df.take(sampler) #使用take使用随机数组进行排列
-
选取随机子集,在Series和DataFrame上使用
sample()
-
要通过替换的方式产生样本(允许重复选择),可以传递replace=True到sample
-
choices = pd.Series([5, 7, -1, 6, 4]) draws = choices.sample(n=10, replace=True)
-
计算指标/哑变量
-
常用于统计建模或机器学习的转换方式是:将分类变量(categorical variable)转换为“哑变量”或“指标矩阵”
-
如果DataFrame的某一列中含有k个不同的值,则可以派生出一个k列矩阵或DataFrame(其值全为1和0)。pandas有一个get_dummies函数可以实现该功能(其实自己动手做一个也不难)。使用之前的一个DataFrame例子
-
df = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],'data1': range(6)}) pd.get_dummies(df['key'])
-
-
DataFrame的列加上一个前缀,以便能够跟其他数据进行合并,get_dummies的prefix参数可以实现该功能
字符串操作
字符串对象方法
pandas的矢量化字符串函数
-
通过data.map,所有字符串和正则表达式方法都能被应用于(传入lambda表达式或其他函数)各个值,但是如果存在NA(null)就会报错
-
data.str.contains('gmail')
通过str.contains检查各个电子邮件地址是否含有"gmail"