Python数据科学—pandas数据包
一、pandas包基础简介二、pandas处理缺失值1.发现缺失值2.剔除缺失值3.填充缺失值三、层级索引1.显式地创建多级索引2.多级索引行列转换1.有序和无序的索引2.索引stack和unstack3.索引的设置 四、合并数据集:concat与append操作 1.通过pd.concat实现简易合并 2.类似join的合并 3.append()方法 五、累计与分组 1.pandas的累计方法 2.group.by应用 1.过滤 2.转换
一、pandas包基础简介
pandas属于python下的一种数据分析包,最初是应用于金融数据分析工具而开发出来的,因此pandas为时间序列分析提供了很好的支持,pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。你很快就会发现,它是使python成为强大而高效的数据分析环境的重要因素之一。
二、pandas处理缺失值
isnull() #创建一个人布尔类型的掩码标签缺失值
notnull() #与isnull操作相反
dropna() #返回一个剔除缺失值的数据
fillna() #返回一个填充了缺失值的数据副本
1.发现缺失值
pandas数据结构有二种有效方法可以发现缺失值:isnull()和notnull()。每种方法返回布尔类型的掩码数据,例如:
IN[1]:data = pd.series([1,nap.nan,'hello'.None])
IN[1]:data.isnull()
Out[1]: 0 False
1 True
2 False
3 True
dtype: bool
布尔类型掩码数组可以直接作为series或者DataFrame的索引使用。
IN[2]: data[data.notnill()]
Out[2]: 0 1
2 hello
dtype: object
在series里使用的insull()和notnull同样适用于DataFrame,产生的结果同样是布尔类型。
2.剔除缺失值
使用dropna()(剔除缺失值)和fillna()(填充缺失值)。
IN[3]: data.dropma()
OUT[3]: 0 1
2 hello
dtype: object
#将有缺失值的行全部剔除,默认情况下dropna()会剔除任何包含缺失值的整行数据
#可以设置接不同的坐标轴别除缺失值,比如axts=1(或axis='coLumns')会剔除#任何#包含缺失值的整列数据
#这么做也会把非缺失值一并别除,因为可能有时候只需剔除全部是缺失值的行或列,或者绝大多数是缺失值的行或列。这些需求可以通过设置how或thresh参数来满足,它们可以设置剔除行或列缺失值的数量阀值
#默认设置是how=any,也就是说只要有缺失值就剔除整行或整列(通过axts设置坐标)。你还可以设置how=all就只会剔除全部是缺失值的行或列
#还可以通过thresh参数设置行或者列中非缺失值的最小数量,从而实现更加个性化的配置
3.填充缺失值
当不想移除缺失值,而是想替换成有效数值。不仅可以通过isnull()方法建立掩码填充缺失值,但是pandas为此专门提供了一个fillna()方法,他将返回填充了缺失值后的数值副本。
IN[4]: data
OUT[4]: a 1.0
b NaN
c 2.0
d NaN
e 3.0
#使用单独的值来填充缺失值,例如用5:
IN[5]:data.fillna(5)
OUT[5]: a 1.0
b 5.0
c 2.0
d 5.0
e 3.0
#可以用缺失值前面的有效值来从前往后填充(forward-fill):
IN[6]: data.fillna(method='ffill')
OUT[6]: a 1.0
b 1.0
c 2.0
d 2.0
e 3.0
#可以用缺失值后面的有效值来从后往前填充(back-fill):
IN[7]: data.fillna(method='bfill')
OUT[7]: a 1.0
b 2.0
c 2.0
d 3.0
e 3.0
三、层级索引
1.显式地创建多级索引
你可以用pd.MultiIndex中的类方法更加灵活地构建多级索引.例如,你可以通过一个有不同等级的若干简单数组组成的列表来构建MultiIndex:
IN[8]pd.MultiIndex.from_arrays([['a','a','b','b'],[1,2,1,2]])
OUT[8]: MultiIndex(levels=[['a','b'],[1,2]]
labels=[[0,0,1,1],[0,1,0,1]])
也可以通过包含多个索引值的元组构成的列表创建MultiIndox;
IN[9]pd.MultiIndex.from_tuples([('a',1),('a',2),('b',1),('b',2)])
OUT[9]: MultiIndex(levels=[['a','b'],[1,2]]
labels=[[0,0,1,1],[0,1,0,1]])
还可以用两个索引的笛卡尔积(Cartesian product)创建MultiIndex:
IN[10]pd.MultiIndex.from_product([['a','b'],[1,2]])
OUT[10]: MultiIndex(levels=[['a','b'],[1,2]]
labels=[[0,0,1,1],[0,1,0,1]])
更可以直接提供levels(包含每个等级的索引值列表的列表)和labels(包含每个索引值标签列表的列表)创建MultiIndex:
IN[11]pd.MultiIndex(levels=[['a','b'],[1,2]],
labels=[[0,0,1,1],[0,1,0,1]])
OUT[11]:MultiIndex(levels=[['a','b'],[1,2]],
labels=[[0,0,1,1],[0,1,0,1]])
2.多级索引行列转换
使用多级索引的关键是掌握有效数据转换的方法。Pandas提供了许多操作,可以让数
据在内容保持不变的同时,按照需要进行行列转换。
1.有序和无序的索引
注意! 如果MultiIndex不是有序的索引,那么大多数切片操作都会失败。,为此pandas提供了许多便捷的操作完成排序,如sort_index()和sortlevel()方法。
IN[12]index = pd.MultiIndex.from_product([['a','c','b'],[1,2]])
data = pd.series(np.random.rand(6),index=index)
data.index.names = ['char','int']
data = data.sort_index()
data
OUT[12]:char int
a 1 0.003001
2 0.164974
b 1 0.001693
2 0.526226
c 1 0.741650
2 0.569264
#再使用局部切片
IN[13]: data['a':'b']
OUT[13]: char int
a 1 0.003001
2 0.164974
b 1 0.001693
2 0.526226
2.索引stack和unstack
IN[14]: pop.unstack(level=0)
OUT[14]: state California New York Texas
year
2000 33871648 18976457 20851820
2010 37253956 19378102 25145561
IN[15]: pop.unstack(level=1)
OUT[15]: year 2000 2010
state
California 33871648 37253956
New York 18976457 19378102
Texas 20851820 25145561
#unstack()是stack()的逆操作,同时使用这2种方法让数据保持不变。
3.索引的设置
层级数据维度转换的另一种方法是行列标签转换,可以通过reset_index方法实现。如果在上面的人口数据series中使用该方法,则会生成一个列标签中包含之前行索引标签state和year的DataFrame。也可以用数据的name属性为列设置名称:
IN[16]: pop_flat = pop.reset_index(name='population')
pop_flat
OUT[16]: state year population
0 California 2000 33871648
1 California 2010 37253956
2 New York 2000 18976457
3 New York 2010 19378102
4 Texas 2000 20851820
5 Texas 2010 25145561
四、合并数据集:concat与append操作
1.通过pd.concat实现简易合并
pandas语法和np.concatenate语法类似,但是配置参数更多,功能也更强大:
IN[17]: x = make_df('AB', [0,1])
pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,keys=None,
levels=None, names=None, verify_integrity=False,copy=True)
pd.concat()可以简单地合并一维的series或者DataFrame对象,也可以用来合并高维数据,默认情况下,DataFrame的合并都是逐行进行的(默认设置是axies=0),也可以自行设置合并坐标轴。
1.索引重复
np.cocatenate与pd.concat最主要的差异之一就是Panas在合并时会保留索引,即使索引是重复的!例如下面的简单示例:
IN[18]: x = make_df('AB', [0,1])
y = make_df('AB', [2,3])
y.index = x.index #复制索引
print(x); print(y); print(pd.concat[x, y])
x y pd.concat([x, y])
A B A B A B
0 A0 B0 0 A2 B2 0 A0 B0
1 A1 B1 1 A3 B3 1 A1 B1
0 A2 B2
1 A3 B3
#此时可以发现结果中索引值为重复的,pd.concat()为此提供了一些解决的方案。
(1)忽略索引
有时索引无关紧要,那么合并时就可以忽略它们,可以通过设置ignore_index参数来实现。
如果将参数设置为True,那么合并时将会创建一个新的整数索引。
IN[19]: print(x); print(y); print(pd.concat([x, y], ignore_index=True))
x y pd.concat([x, y], ignore_index=True)
A B A B A B
0 A0 B0 0 A2 B2 0 A0 B0
1 A1 B1 1 A3 B3 1 A1 B1
2 A2 B2
3 A3 B3
(2)增加多级索引
还可以通过keys参数为数据源设置多级索引标签,这样结果数据可以带上多级索引
IN[20]: print(x); print(y); print(pd.concat([x, y], ignore_index=True))
x y pd.concat([x, y], keys=['x', 'y'])
A B A B A B
0 A0 B0 0 A2 B2 0 A0 B0
1 A1 B1 1 A3 B3 1 A1 B1
0 A2 B2
1 A3 B3
2.类似join的合并
前面合并的都是同样列名的dataframe,但是在日常工作中往往会需要合并不同列名的数据,而pd.concat提供了一些选项来解决这些问题,例如:
IN[21]: df5 = make_df('ABC', [1, 2])
df6 = make_df('ABC', [3, 4])
print(df5); print(df6); print(pd.concat([df5, df6])
df5 df6 pd.concat([df5, df6])
A B C B C D A B C D
1 A1 B1 C1 3 B3 C3 D3 1 A1 B1 C1 NaN
2 a2 b2 c2 4 B4 C4 D4 2 A2 B2 C2 NaN
3 NaN B3 C3 D3
4 NaN B4 C4 D4
默认情况下,某个位置上缺失的数据会用NaN表示。如果不想这样,可以用join和join_axes参数设置合并方式。默认的合并方式是对所以输入列进行并集合并(join='outer'),当然也可以用join='inner'实现对输入列的交集合并:
IN[21]: print(df5); print(df6);
print(pd.concat([df5, df6], join='inner'))
df5 df6 pd.concat([df5, df6],join='inner')
A B C B C D B C
1 A1 B1 C1 3 B3 C3 D3 1 B1 C1
2 a2 b2 c2 4 B4 C4 D4 2 B2 C2
3 B3 C3
4 B4 C4
#另一种合并方式是直接确定结果使用的列名,设置join_axes参数,里面是索引对象构成的列表(是列表的列表)。将结果的列名设置为第一个输入的列名:
IN[22]: print(df5); print(df6);
print(pd.concat([df5, df6], join_axes=[df5.columns]))
df5 df6 pd.concat([df5, df6],join_axes=[df5.columns]])
A B C B C D A B C
1 A1 B1 C1 3 B3 C3 D3 1 A1 B1 C1
2 a2 b2 c2 4 B4 C4 D4 2 A2 B2 C2
3 NaN B3 C3
4 NaN B4 C4
3.append()方法
因为直接进行数组合并的需求非常普遍,所以Series和DataFrame对象都支持append方法,让你通过最少的代码实现合并功能。例如,你可以使用df1.append(df2),效果与pd.concat([df1,df27)一样:
IN[23]: print(df1); print(df2);print(df1.append(df2))
df1 df2 df1.append(df2)
A B A B A B
1 A1 B1 3 A3 A3 1 A1 B1
2 a2 b2 4 A4 A4 2 A2 B2
3 A3 B3
4 A4 B4
需要注意的是、与Python列表中的append()和extend()方法不同,Pandas的append()不直接更新原有对象的值,而是为合并后的数据创建一个新对象。因此,它不能被称之为一个非常高效的解决方案,因为每次合并都需要重新创建索引和数据缓存。总之,如果你需要进行多个append操作,还是建议先创建一个DataFrame列表,然后用concat()函数一次性解决所有合并任务。
五、累计与分组
1.pandas的累计方法
指标 | 描述 |
---|---|
count() | 计数项 |
first() | 第一项和最后一项 |
mean(),median() | 均值与中位数 |
min(),max() | 最小值与最大值 |
std(),var() | 标准差与方差 |
mad() | 均值与绝对差 |
prod() | 所有项乘积 |
sum() | 所有项求和 |
2.group.by应用
1.过滤
可以按照分组的属性丢弃若干数据。例如我们可能只需要保留超过标准差超过某个阈值的组:
IN[24]:
def filter_func(x):
return x['data2'].std()>4
print(df); print(df.groupby('key').std());
print(df.groupby('key').filter(filter_func))
df df.groupby('key').std()
key data1 data2 key data1 data2
0 A 0 5 A 2.12132 1.414214
1 B 1 0 B 2.12132 4.949747
2 C 2 3 C 2.12132 4.242641
3 A 3 3
4 B 4 7
5 C 5 9
df.groupby('key').filter(filter_func)
key data1 data2
1 B 1 0
2 C 2 3
4 B 4 7
5 C 5 9
#filter()函数会返回一个布尔值,表示每个组是否通过过滤。由于A组'data2'列的标准差不大于4,所以被丢弃。
2.转换
累计操作返回的是对组内全量数据缩减过的结果,而转换操作会返回一个新的全量数据。数据经过转换之后,其形状与原来的输入数据是一样的。常见的例子就是将每组的样本数据减去各组的均值,实现数据标准化:
IN[25]:df.groupby('key').transform(lambda x: x - x.mean())
OUT[25]: data1 data2
0 -1.5 1.0
1 -1.5 -3.5
2 -1.5 -3.0
3 -1.5 -1.0
4 -1.5 3.5
5 -1.5 3.0
参考文献:
《python数据科学手册》 Jack Vanderplas[美]