python 数据分析3
Posted Dandy Zhang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 数据分析3相关的知识,希望对你有一定的参考价值。
本节概要
pandas简介
安装
pip install pandas
pandas的2个主要数据结构:DataFrame 和 Series
Series
series是一种类似于一维数组的对象,它由一组数据以及一组与之相关的数据标签(索引)组成。仅由一组数组即可产生最简单的Series:
obj = Series([4, 7, 9, -1]) print(obj) 0 4 1 7 2 9 3 -1 dtype: int64
Series的字符串表现形式为索引在左边,值在右边。没有设定索引,会自动穿件一个0~N-1的整数型索引。
obj = Series([4, 7, 9, -1]) print(obj.values) print(obj.index) [ 4 7 9 -1] RangeIndex(start=0, stop=4, step=1)
创建一个含有自定义索引的series
obj = Series([4, 7, 9, -1], index=[\'a\', \'b\', \'c\', \'d\']) print(obj) print(obj.index) a 4 b 7 c 9 d -1 dtype: int64 Index([\'a\', \'b\', \'c\', \'d\'], dtype=\'object\')
索引取值
obj[\'a\'] ==> 4 obj[\'c\'] ==> 9 obj[\'a\', \'d\'] ==> 4, -1
NumPy数组运算都会保留索引跟值之间的链接:
obj[obj>2] a 4 b 7 c 9 dtype: int64 obj*2 a 8 b 14 c 18 d -2 dtype: int64
series可以看成是一个有序字典,因为存在index到value的一个映射关系。可以应用在许多原本需要字典参数的函数中:
\'b\' i obj ==> True
如果数据存放在Python字典中,也可以直接用字典穿件series:
dict_obj = {"a":100,"b":20,"c":50,"d":69} obj = Series(dict_obj) dict_obj a 100 b 20 c 50 d 69 dtype: int64
如果传入一个字典,还有index列表:
dict_obj = {"a":100,"b":20,"c":50,"d":69} states = [\'LA\',\'b\',\'a\',\'NY\'] obj = Series(dict_obj, index=states) LA NaN b 20.0 a 100.0 NY NaN dtype: float64
我们发现匹配项会被找出来放在相应的位置,而没有匹配的则用NAN(not a number)表示缺失。pandas的isnull 和notnull函数可以用于检测数据缺失:
pd.isnull(obj) LA True b False a False NY True dtype: bool
Series也有类似的用法:
obj.isnull() LA True b False a False NY True dtype: bool
Series 最重要的一个功能是:它在算术运算中会自动对齐不同索引的数据
dict_obj = {"a":100,"b":20,"c":50,"d":69} dict_obj1 = {"e":100,"b":20,"c":50,"f":69} obj = Series(dict_obj) obj1 = Series(dict_obj1) obj+obj1 a NaN b 40.0 c 100.0 d NaN e NaN f NaN dtype: float64
Series对象的name属性
obj.name=\'qty\' obj.index.name = \'types\' types a 100 b 20 c 50 d 69 Name: qty, dtype: int64
Series索引可以通过赋值的方式就地修改:
obj.index = [\'dandy\',\'renee\',\'Jeff\',\'Steve\'] obj dandy 100 renee 20 Jeff 50 Steve 69 Name: qty, dtype: int64
DataFrame
dataframe是一个表格型的数据结构,它含有一组有序列,每列可以是不通的值的类型。DataFrame既有行索引,又有列索引,它可以看成是series组成的字典(共用同一个索引)。
构建DataFrame
data = {\'states\':[\'NY\', \'LA\', \'CA\', \'BS\', \'CA\'], \'year\':[2000, 2001, 2002, 2001, 2000], \'pop\':[1.5, 1.7, 3.6, 2.4, 2.9]} frame = DataFrame(data) frame pop states year 0 1.5 NY 2000 1 1.7 LA 2001 2 3.6 CA 2002 3 2.4 BS 2001 4 2.9 CA 2000
指定列序列
frame2 = DataFrame(data, columns=[\'year\', \'pop\', \'states\', \'test\'])
frame2.columns year pop states test 0 2000 1.5 NY NaN 1 2001 1.7 LA NaN 2 2002 3.6 CA NaN 3 2001 2.4 BS NaN 4 2000 2.9 CA NaN
Index([\'year\', \'pop\', \'states\', \'test\'], dtype=\'object\') # 不存在的列就会产生NaN值
取值:
# 取一列数据的2种方式 frame2[\'states\'] frame2.year 0 NY 1 LA 2 CA 3 BS 4 CA Name: states, dtype: object 0 2000 1 2001 2 2002 3 2001 4 2000 Name: year, dtype: int64 # 返回一个series # 修改行索引 DataFrame(data, columns=[\'year\', \'pop\', \'states\', \'test\'], index=[\'one\', \'two\', \'three\', \'four\', \'five\']) year pop states test one 2000 1.5 NY NaN two 2001 1.7 LA NaN three 2002 3.6 CA NaN four 2001 2.4 BS NaN five 2000 2.9 CA NaN 获取列 frame2.ix[\'three\'] year 2002 pop 3.6 states CA test NaN Name: three, dtype: object 列可以通过赋值的方式修改 frame2.test = \'11\' year pop states test one 2000 1.5 NY 11 two 2001 1.7 LA 11 three 2002 3.6 CA 11 four 2001 2.4 BS 11 five 2000 2.9 CA 11
列操作:
将列表或数组赋值给某个列时,其长度必须跟DataFrame的长度相匹配。如果是Series则会精确匹配DataFrame索引,所有空位被填上缺失值
val = Series([-1, -2, 3], index=[\'two\', \'one\', \'three\']) frame2[\'test\'] = val frame2 year pop states test one 2000 1.5 NY -2.0 two 2001 1.7 LA -1.0 three 2002 3.6 CA 3.0 four 2001 2.4 BS NaN five 2000 2.9 CA NaN
为不存在的列赋值,会创建出一列新列。del用于删除,跟python字典用法很像
frame2[\'test1\'] = frame2.test.notnull() frame2 year pop states test test1 one 2000 1.5 NY -2.0 True two 2001 1.7 LA -1.0 True three 2002 3.6 CA 3.0 True four 2001 2.4 BS NaN False five 2000 2.9 CA NaN False
del frame2[\'test1\'] frame2 year pop states test one 2000 1.5 NY -2.0 two 2001 1.7 LA -1.0 three 2002 3.6 CA 3.0 four 2001 2.4 BS NaN five 2000 2.9 CA NaN
嵌套字典创建dataframe
pop = { "dandy":{"age":18, "gender":"male"}, "elina": {"age": 16, "gender": "female"}, "renee": {"age": 16, "gender": "female"}, "taylor": {"age": 18, "gender": "female"}, } frame3 = DataFrame(pop) frame3 dandy elina renee taylor age 18 16 16 18 gender male female female female frame3.T # 转置 age gender dandy 18 male elina 16 female renee 16 female taylor 18 female
series组成的字典创建:
pdata = {\'dandy\': frame3[\'dandy\'][:-1], \'elina\': frame3[\'elina\']} frame4 = DataFrame(pdata) frame4 dandy elina age 18 16 gender NaN female
设置属性名
frame3.index.name = \'detail\' frame3.columns.name = \'name\' frame3 name dandy elina renee taylor detail age 18 16 16 18 gender male female female female
values属性
frame3.values # 以二维ndarray的形式返回dataframe中的数据 [[18 16 16 18] [\'male\' \'female\' \'female\' \'female\']]
索引对象
pandas的索引对象负责管理轴标签和其他元素(轴名称等)。构建series或者dataframe时,所用到的任何数组和其他序列的标签都会被转成一个Index。Index对象是不可修改的(immutable)。
obj = Series(range(3), index=[\'a\', \'b\', \'c\']) Index = obj.index Index[0] a
如果输入Index[0] = \'x\':
正是因为index的不可修改性,才能使Index对象在多个数据结构之间安全共享:
Index = pd.Index(np.arange(3)) obj2 = Series([1.5, -2, 0], index=Index) obj2.index is Index True
除了长得像数组,Index的功能也类似一个固定大小的集合:
pop = { "dandy":{"age":18, "gender":"male"}, "elina": {"age": 16, "gender": "female"}, "renee": {"age": 16, "gender": "female"}, "taylor": {"age": 18, "gender": "female"}, } frame3 = DataFrame(pop) \'dandy\' in frame3.columns True
基本功能
obj = Series([4, 6, 9.9, 7], index=[\'a\', \'v\', \'b\', \'d\']) obj a 4.0 v 6.0 b 9.9 d 7.0 dtype: float64
reindex
obj2 = obj.reindex([\'a\', \'b\', \'c\', \'d\', \'v\']) # 不存在的NaN obj2 a 4.0 b 9.9 c NaN d 7.0 v 6.0 dtype: float64 # 引入fill_value=0 obj2 = obj.reindex([\'a\', \'b\', \'c\', \'d\', \'v\'], fill_value=0) obj2 a 4.0 b 9.9 c 0.0 d 7.0 v 6.0 dtype: float64 #method obj = Series([\'aa\', \'bb\', \'cc\', \'dd\'], index=[0,2,4,6]) obj2 = obj.reindex(range(7), method=\'ffill\') 0 aa 1 aa 2 bb 3 bb 4 cc 5 cc 6 dd dtype: object
frame = DataFrame(np.arange(9).reshape((3,3)), index=[\'a\', \'b\', \'c\'], columns=[\'Ohio\', \'Texas\', \'California\']) frame2 =frame.reindex([\'a\', \'b\', \'c\', \'d\']) frame Ohio Texas California a 0 1 2 b 3 4 5 c 6 7 8 frame2 Ohio Texas California a 0.0 1.0 2.0 b 3.0 4.0 5.0 c 6.0 7.0 8.0 d NaN NaN NaN text = [\'Texas\', \'LA\', \'California\'] frame3 = frame.reindex(columns=text) frame3 Texas LA California a 1 NaN 2 b 4 NaN 5 c 7 NaN 8
同时对行列重新索引,插值只能按行应用(轴0)
text = [\'Texas\', \'LA\', \'California\'] frame.reindex(index=[\'a\',\'b\',\'c\',\'d\',\'e\',\'f\'], method=\'ffill\').reindex(columns=text) Texas LA California a 1 NaN 2 b 1 NaN 2 c 4 NaN 5 d 4 NaN 5 e 7 NaN 8 f 7 NaN 8
利用ix的标签索引功能,重新索引会更简洁,ix(索引,列)
frame.ix[[\'a\',\'b\',\'c\',\'d\'],text] Texas LA California a 1.0 NaN 2.0 b NaN NaN NaN c 4.0 NaN 5.0 d NaN NaN NaN
丢弃指定轴上的项
drop方法,返回的是一个在指定轴上删除了指定值的新对象:
obj = Series(np.arange(5), index=[\'a\',\'b\',\'c\',\'d\',\'e\']) new_obj = obj.drop(\'c\') new_obj a 0 b 1 d 3 e 4 dtype: int32
对于DataFrame,可以删除任意轴上的索引值:
data = DataFrame(np.arange(16).reshape(4,4), index=[\'LA\',\'UH\',\'NY\',\'BS\'], columns=[\'one\',\'two\',\'three\',\'four\']) data.drop([\'LA\',\'BS\']) one two three four UH 4 5 6 7 NY 8 9 10 11 #对于列,axis=1 data.drop([\'one\',\'three\'], axis=1) two four LA 1 3 UH 5 7 NY 9 11 BS 13 15
索引、选取和过滤
Series索引的工作方式类似于NumPy数组的索引,只不过Series的索引值不只是整数。
obj = Series(np.arange(4), index=[\'a\',\'b\',\'c\',\'d\']) obj a 0 b 1 c 2 d 3 dtype: int32 obj[\'b\'] # 或者obj[1] 1 obj[2:4] # 或者obj[[\'c\',\'d\']] c 2 d 3 dtype: int32 obj[[1,3]] b 1 d 3 dtype: int32 obj[obj>2] d 3 dtype: int32
标签切片跟普通的python切片运算不同,其末端是包含的:
obj[\'b\':\'c\'] b 1 c 2 dtype: int32 obj[\'b\':\'c\'] = 5 obj a 0 b 5 c 5 d 3 dtype: int32
对DataFrame进行索引,现在看来就是获取一个或多个列:
data = DataFrame(np.arange(16).reshape((4,4)), index=[\'aa\',\'bb\',\'cc\',\'dd\'], columns=[\'one\',\'two\',\'three\',\'four\']) data[\'two\'] aa 1 bb 5 cc 9 dd 13 Name: two, dtype: int32 data[[\'three\',\'two\']] three two aa 2 1 bb 6 5 cc 10 9 dd 14 13 data[:2] one two three four aa 0 1 2 3 bb 4 5 6 7 data[data[\'three\']>5] one two three four bb 4 5 6 7 cc 8 9 10 11 dd 12 13 14 15
这里可能大家都会对于最后的布尔感到惊讶:
data>5 one two three four aa False False False False bb False False True True cc True True True True dd True True True True data[data<5]=0 data one two three four aa 0 0 0 0 bb 0 5 6 7 cc 8 9 10 11 dd 12 13 14 15
这段代码使DataFrame在语法上更像ndarray。
至于行标签索引,用ix索引字段。它使你可以通过NumPy式的标记法以及轴标签从DataFrame中选取行和列的子集。ix(索引,列)
data.ix[[\'cc\',\'bb\'],[3,0,1]] four one two cc 11 8 9 bb 7 0 5 data.ix[\'dd\',[\'three\',\'two\']] three 14 two 13 Name: dd, dtype: int32 data.ix[2] one 8 two 9 three 10 four 11 Name: cc, dtype: int32 data.ix[:\'cc\',\'two\'] aa 0 bb 5 cc 9 Name: two, dtype: int32 data.ix[data.three>5,:3] one two three bb 0 5 6 cc 8 9 10 dd 12 13 14
数据运算和数据对齐
算术运算:
s1 = Series([7.3, -2.5, 3.4, 1.5], index=[\'a\',\'b\',\'c\',\'e\']) s2 = Series([2.3, -2.4, 6.9, 8.1], index=[\'a\',\'c\',\'d\',\'f\']) s1 a 7.3 b -2.5 c 3.4 e 1.5 dtype: float64 s2 a 2.3 c -2.4 d 6.9 f 8.1 dtype: float64 s3 a 9.6 b NaN c 1.0 d NaN e NaN f NaN dtype: float64
可以发现自动的数据对齐操作,在不重叠的索引出直接引入了NaN值。缺失值会在datafram运算过程中传播,对齐操作同时作用在行和列上。
df1 = DataFrame(np.arange(9).reshape((3,3)),columns=list(\'bcd\'), index=[\'aa\',\'bb\',\'cc\']) df2 = DataFrame(np.arange(12).reshape((4,3)),columns=list(\'abc\'), index=[\'aa\',\'cc\',\'dd\',\'ee\']) df1 b c d aa 0 1 2 bb 3 4 5 cc 6 7 8 df2 a b c aa 0 1 2 cc 3 4 5 dd 6 7 8 ee 9 10 11 df1 + df2 a b c d aa NaN 1.0 3.0 NaN bb NaN NaN NaN NaN cc NaN 10.0 12.0 NaN dd NaN NaN NaN NaN ee NaN NaN NaN NaN
在算术方法中填充值
df1 = DataFrame(np.arange(9).reshape((3,3)),columns=list(\'bcd\')) df2 = DataFrame(np.arange(20).reshape((4,5)),columns=list(\'abcde\')) df1.add(df2, fill_value=0) a b c d e 0 0.0 1.0 3.0 5.0 4.0 1 5.0 9.0 11.0 13.0 9.0 2 10.0 17.0 19.0 21.0 14.0 3 15.0 16.0 17.0 18.0 19.0
类似的,在对Series和DataFrame重新索引时,也可以指定一个填充值:
df1.reindex(columns=df2.columns, fill_value=0) a b c d e 0 0 0 1 2 0 1 0 3 4 5 0 2 0 6 7 8 0
加减乘除:add、sub、mul、div
DataFrame和Series之间的运算
先看个例子:
arr = np.arange(12).reshape((3,4)) arr [[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] arr[0] [0 1 2 3] arr - arr[0] [[0 0 0 0] [4 4 4 4] [8 8 8 8]]
发现所有的维度都被减了,这个就是广播。
frame = DataFrame(np.arange(12).reshape((4,3)), columns=list(\'bcd\'), index=[\'Utah\', \'Ohio\',\'Texas\',\'Pregon\']) series = frame.ix[0] frame b c d Utah 0 1 2 Ohio 3 4 5 Texas 6 7 8 Pregon 9 10 11 series b 0 c 1 d 2 Name: Utah, dtype: int32 frame - series b c d Utah 0 0 0 Ohio 3 3 3 Texas 6 6 6 Pregon 9 9 9 # 行广播运算
如果某个索引值在DataFrame的列或Series的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集
series2 = Series(range(3), index=[\'b\',\'c\',\'f\']) frame+series2 b c d f Utah 0.0 2.0 NaN NaN Ohio 3.0 5.0 NaN NaN Texas 6.0 8.0 NaN NaN Pregon 9.0 11.0 NaN NaN
如果希望匹配行,且在列广播,就必须用算术云算法。
series3 = frame[\'d\'] series3 Utah 2 Ohio 5 Texas 8 Pregon 11 Name: d, dtype: int32 frame.sub(series3, axis=0) b c d Utah -2 -1 0 Ohio -2 -1 0 Texas -2 -1 0 Pregon -2 -1 0
函数的应用和映射
NumPy的ufuncs(元素级数组方法)也可用于操作pandas对象:
frame = DataFrame(np.random.randn(4,3), columns=list(\'bcd\'), index=[\'Utah\', \'Ohio\',\'Texas\',\'Pregon\']) np.abs(frame) b c d Utah 1.953494 1.379303 0.338753 Ohio 1.142983 0.953289 0.843422 Texas 0.557409 1.798355 1.019692 Pregon 0.193954 1.787517 0.723089
另一个常见操作是,将函数应用到各列或行所形成的一维数组上。DataFrame的apply方法可以实现
f = lambda x:x.max() - x.min() frame.apply(f,axis=1) Utah 2.339517 Ohio 1.089608 Texas 1.393819 Pregon 1.881294 dtype: float64 frame.apply(f) b 1.214805 c 2.756908 d 1.997903 dtype: float64
传递给apply的函数还可以返回多个值组成的Series:
def foo(x): return Series([x.min(), x.max()], index=[\'min\', \'max\']) frame.apply(foo) b c d min -0.343971 -2.44858 -1.736360 max 1.113326 0.96367 0.067587
此外,元素级的python函数也是可以用的。假如你想得到frame中各个浮点值的格式化字符串
format = lambda x: \'%.2f\' % x frame.applymap(format) b c d Utah -0.26 -0.59 0.93 Ohio 0.01 -0.28 0.37 Texas 0.40 -1.32 -0.55 Pregon 0.20 -1.07 0.04
之所以叫做applymap是因为Series有一个用于应用元素级函数的map方法:
frame[\'d\'].map(format) Utah -0.67 Ohio 0.14 Texas 0.11 Pregon -0.72 Name: d, dtype: object
排序和排名
1、索引排序
sort_index 行排序,默认是升序排序的。
对于dataframe而言可以对任意一个轴上的索引排序:
frame.sort_index(axis=1) # 列排序
frame.sort_index(axis=1,ascending=False)
# sort_index已经存在一个future warning,后续将不在支持,转而使用sort_values方法
2、值排序
Series直接用order() # order在新版本已经不存在可以使用sort_vaues来代替
obj.order() # 任何缺失值都会被放到Series的末尾
在DataFrame上,你可能希望根据一个或者多个列排序。我们通过把一个或多个列的列名传递给by即可达到目的:
frame.sort_index(by=\'column1\')
frame.sort_index(by=[\'column1\', \'column2\'])
3、排名(ranking)
排名跟排序关系密切,且它会增设一个排名值,从1开始,一直到数组中有效数据的数量。它跟numpy.argsort产生的间接排序索引差不多,只不过它可以根据某种规则破坏平级关系。Series和DataFrame的rank方法在默认情况下,rank是通过为各组分配一个平均排名的方式破坏平级关系。
obj = Series([7,-5,7,4,2,0,4]) obj.rank() 0 6.5 1 1.0 2 6.5 3 4.5 4 3.0 5 2.0 6 4.5 dtype: float64
也可以根据值在原始数据中出现的顺序给出排名:
obj.rank(method=\'first\') 0 6.0 1 1.0 2 7.0 3 4.0 4 3.0 5 2.0 6 5.0 dtype: float64
也可以按降序进行排名:
obj.rank(ascending=False, method=\'max\') 0 2.0 1 7.0 2 2.0 3 4.0 4 5.0 5 6.0 6 4.0 dtype: float64
DataFrame可以在行或者列上计算排名:
frame = DataFrame({\'b\':[4.3,7,-3,2] ,\'a\':[0,1,0,1], \'c\':[-2,5,8,-2.5]}) frame a b c 0 0 4.3 -2.0 1 1 7.0 5.0 2 0 -3.0 8.0 3 1 2.0 -2.5 frame.rank(axis=1) a b c 0 0 4.3 -2.0 1 1 7.0 5.0 2 0 -3.0 8.0 3 1 2.0 -2.5
1 排名时用于破坏平级关系的method选项 2 average 默认:在相等分组中,为各个值分配平均排名 3 min 使用整个分组的最小排名 4 max 使用整个分组的最大排名 5 first 按值在原始数据中的出现顺序分配排名
带有重复值的轴索引
之前介绍的所有范例都是唯一的轴标签,虽然pandas函数我们都要求标签唯一,但这并不是强制的。
obj = Series(range(5), index=[\'a\',\'b\',\'a\',\'b\',\'e\']) obj.index.is_unique false # index里面的is_unique属性可以检测唯一性 #获取值 obj[\'a\'] 2个 obj[\'e\'] 1个 dataframe的重复索引,会拉出满足索引的所有行。 frame.ix[\'b\']
汇总和统计
frame = DataFrame([[1.4,np.nan],[7.1,-4],[np.nan,np.nan],[0.73,-1]], index=[\'a\',\'b\',\'c\',\'d\'], columns=[\'one\',\'two\']) frame.sum() one 9.23 two -5.00 dtype: float64 #sum函数将返回一个含有列小计的series,默认axis=0 frame.sum(axis=1) a 1.40 b 3.10 c 0.00 d -0.27 dtype: float64、 #不忽略NA值 frame.mean(axis=1, skipna=False) a NaN b 1.550 c NaN d -0.135 dtype: float64
间接统计
frame.idxmax() one b two d dtype: object frame.cumsum() one two a 1.40 NaN b 8.50 -4.0 c NaN NaN d 9.23 -5.0 # describe针对数值型 frame.describe() one two count 3.000000 2.00000 mean 3.076667 -2.50000 std 3.500376 2.12132 min 0.730000 -4.00000 25% 1.065000 -3.25000 50% 1.400000 -2.50000 75% 4.250000 -1.75000 max 7.100000 -1.00000 # describe针对于非数值型 obj = Series([\'a\',\'a\',\'b\',\'c\']*4) obj.describe() count 16 unique 3 top a freq 8 dtype: object
相关系数与协方差
# 计算价格的百分数变化 frame_returns = frame.pct_change() frame_returns.tail() # 返回末尾的5行 #Seriesde corr方法用于计算两个Series中的重叠的,非NA的,按索引对齐的值的相关系数。cov用于计算协方差。 frame_returns[\'a\'].corr(frame_returns[\'b\']) frame_returns[\'a\'].cov(frame_returns[\'b\']) #dataframe的 corr和cov方法将以dataframe的形式返回完整的相关系数或协方差矩阵: frame_returns.corr() frame_returns.cov() #dataframe的corrwith方法,可以用来计算其列或行跟另一个Series或dataframe之间的相关系数。传入一个series将会返回一个相关系数值Series frame_returns.corrwith(frame_returns[\'a\']) #传入一个dataframe则会计算按列名配对的相关系数。 frame_returns.corrwith(frame1)
唯一值,值计数以及成员资格
obj = Series([\'c\',\'a\',\'b\',\'a\',\'c\',\'b\',\'a\',\'b\',\'c\',\'d\']) unique = obj.unique() unique [\'c\' \'a\' \'b\' \'d\'] sorted(unique) [\'a\', \'b\', \'c\', \'d\'] #统计series中各个值出现的频率,默认降序 c 3 b 3 a 3 d 1 dtype: int64 #value_counts还是一个顶级的pandas方法,可以用于任何数组和序列: pd.value_counts(obj.values, sort=False) # isin用来判断矢量化集合的成员资格。 mask = obj.isin([\'b\',\'c\']) 0 True 1 False 2 True 3 False 4 True 5 True 6 False 7 True 8 True 9 False dtype: bool obj[mask] 0 c 2 b 4 c 5 b 7 b 8 c dtype: object
有时希望得到dataframe中多个相关列的一个柱状图。
data = DataFrame({\'q1\':[1,2,2,4,5],
\'q2\':[2,3,4,4,6],
\'q3\':[3,4,5,7,1]})
这时我们可以联想到一个apply函数,可以接收方法函数:
result = data.apply(pd.value_counts).fillna(0) result q1 q2 q3 1 1.0 0.0 1.0 2 2.0 1.0 0.0 3 0.0 1.0 1.0 4 1.0 2.0 1.0 5 1.0 0.0 1.0 6 0.0 1.0 0.0 7 0.0 0.0 1.0
缺失数据处理
NaN:pandas使用浮点值NaN表示浮点和非浮点数组中的缺失数据。它只是一个便于被检测出来的标记而已:
string_data.isnull()
Python内置的None值也会被当做NA处理。
滤除缺失数据
Series
data = Series([1,NA,3.8,NA,9]) data.dropna() 0 1.0 2 3.8 4 9.0 dtype: float64 # 也可以用索引来取值,True data[data.notnull()] 0 1.0 2 3.8 4 9.0 dtype: float64
DataFrame就有点复杂了,因为是多维的所以必须考虑维度了。你可能会考虑丢弃全NA的行或者列。
data = DataFrame([[1,6.5,7],[1,NA,5],[NA,NA,NA],[NA,6.5,3]]) cleaned = data.dropna() cleaned 0 1 2 0 1.0 6.5 7.0 # 只丢弃全NA的行 data.dropna(how=\'all\') # 组合 data.dropna(axis=1,how=\'all\')
另一个滤除DataFrame行的问题设计时间序列数据。假设你只想留下一部分观测数据可以用thresh参数实现此目的:至少要有thresh个非NA值
df = df.DataFrame(np.random.randn(7, 3)) df.ix[:4, 1] = NA; df.ix[:2, 2] = NA df 0 1 2 0 -0.776521 NaN NaN 1 -1.179873 NaN NaN 2 -0.479620 NaN NaN 3 -0.214146 NaN -0.387709 4 0.864021 NaN -1.198854 5 -1.654861 -1.367580 -1.010236 6 0.454499 0.938988 -0.511850 df.dropna(thresh=3) 0 1 2 5 -1.654861 -1.367580 -1.010236 6 0.454499 0.938988 -0.511850
缺失数据的填充
fillna方法将缺失值替换为常数值:
df.fillna(0)
不同的列填不同的值:
frame.fillna({1:0.5,2:-2})
fillna默认会返回新对象,但也可以对现有对象进行就地修改:
frame.fillna(0,inplace=True)
总是返回被填充对象的引用。
对于reindex有效的那些插值方法也可用于fillna:
frame.fillna(method=\'ffill\',limit=2) #限制只能向前填充2个
思维活跃一点,我们可以向空的地方传入平均值,中位数
data.fillna(data.mean())
层次化索引
pandas的一项重要功能,它使你能在一个轴上拥有多个索引级别,它使你能以低纬度形式处理高纬度数据
data = Series(np.random.randn(10), index=[[\'a\',\'a\',\'a\',\'b\',\'b\',\'b\',\'c\',\'c\',\'d\',\'d\'], [1,2,3,1,2,3,1,2,2,1]]) data a 1 -0.165922 2 -0.138976 3 0.007587 b 1 0.335639 2 1.629216 3 -0.480855 c 1 -2.172897 2 -0.171582 d 2 -0.289778 1 -2.916143 dtype: float64
这就是带有multiIndex索引的格式化输出形式。索引之间的间隔表示直接使用上面的标签:
data.index MultiIndex(levels=[[\'a\', \'b\', \'c\', \'d\'], [1, 2, 3]], labels=[[0, 0, 0, 1, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 1, 0]])
层次化索引对象,选取数据子集的操作很简单:
data[\'b\'] 1 0.247669 2 0.975361 3 -0.308308 dtype: float64 data[\'b\':\'c\'] b 1 1.163305 2 0.815069 3 -0.154085 c 1 -0.912454 2 0.705557 dtype: float64 data.ix[[\'b\',\'d\']] b 1 1.757426 2 -0.150988 3 0.222278 d 2 0.602902 1 -0.388132 dtype: float64 #所有一级轴内的,二级索引中的2 data[:,2] a -0.858922 b 0.292737 c 1.174298 d -0.037061 dtype: float64
层次化索引数据重塑与分组
data.unstack() 1 2 3 a 1.159234 -0.429165 -0.625657 b -0.279153 1.500612 1.306801 c -0.517813 0.694927 NaN d 0.442514 -0.012561 NaN data.unstack().stack() # unstack的逆运算是stack
DataFrame每条轴上都可以分层索引:
frame = DataFrame(np.arange(12).reshape((4,3)), index=[[\'a\',\'a\',\'b\',\'b\'],[1,2,1,2]], columns=[[\'ohio\',\'ohio\',\'LA\'],[\'green\',\'ren\',\'yellow\']]) frame ohio LA green ren yellow a 1 0 1 2 2 3 4 5 b 1 6 7 8 2 9 10 11 frame.index.names=[\'key1\',\'key2\'] frame.columns.names = [\'state\',\'color\'] state ohio LA color green ren yellow key1 key2 a 1 0 1 2 2 3 4 5 b 1 6 7 8 2 9 10 11
有了分部的索引,就可以轻松选取索引分组了
frame[\'ohio\']
重新分级排序
frame.swaplevel(\'key1\',\'key2\') state ohio LA color green ren yellow key2 key1 1 a 0 1 2 2 a 3 4 5 1 b 6 7 8 2 b 9 10 11 # sortlevel根据单个级别中的值对数据进行排序。交换级别时,常常也会伴随着sortlevel,这样结果就有序了。 frame.sortlevel(1) state ohio LA color green ren yellow key1 key2 a 1 0 1 2 b 1 6 7 8 a 2 3 4 5 b 2 9 10 11 frame.swaplevel(0,1).sortlevel(0) state ohio LA color green ren yellow key2 key1 1 a 0 1 2 b 6 7 8 2 a 3 4 5 b 9 10 11
根据级别汇总统计
frame.sum(level=\'key2\') state ohio LA color green ren yellow key2 1 6 8 10 2 12 14 16 frame.sum(level=\'color\',axis=1) color green ren yellow key1 key2 a 1 0 1 2 2 3 4 5 b 1 6 7 8 2 9 10 11
dataframe的列转行索引:
frame2 = frame.set_index([\'c\',\'d\']) frame2 a b c d one 0 0 7 1 1 6 2 2 5 two 0 3 4 1 4 3 2 5 2 3 6 1 # 默认列会被删除,也可以保留 frame2 = frame.set_index([\'c\',\'d\'],drop=False) frame2 a b c d c d one 0 0 7 one 0 1 1 6 one 1 2 2 5 one 2 two 0 3 4 two 0 1 4 3 two 1 2 5 2 two 2 3 6 1 two 3 frame2.reset_index() c d a b 0 one 0 0 7 1 one 1 1 6 2 one 2 2 5 3 two 0 3 4 4 two 1 4 3 5 two 2 5 2 6 two 3 6 1
其他有关pandas的话题
整数索引
首先,看一个实例,下面的代码会输出什么
ser = Series(np.arange(3)) ser[-1]
从python切片的角度,应该输出ser的最后一位。但在这种情况下,虽然pandas会‘求助于整数索引’,但没有哪种方法能够既不引入任何的bug又安全有效的解决该问题。因为本身存在0,1,2的索引,所以很难推断出用户想要什么。
然而对于一个非整数索引,就没有这样的歧义:
ser2 = Series(np.arange(3),index=[\'a\',\'b\',\'c\']) ser2[-1] 2
ix方法现在已经被loc和iloc方法取代,在dataframe里面,irow同理也是被loc和iloc取代。
loc是label索引, iloc是位置索引
看个简单的示例
面板数据
对于多维的dataframe用.to_frame()呈现面板数据。to_panel方法是to_frame的逆运算。
看书吧,。。159页,这个真不会忽悠人。
以上是关于python 数据分析3的主要内容,如果未能解决你的问题,请参考以下文章
[未解决问题记录]python asyncio+aiohttp出现Exception ignored:RuntimeError('Event loop is closed')(代码片段