一、Pandas基础
Pandas是基于NumPy的一套数据分析工具,该工具是为了解决数据分析任务而创建的,所以它至少有以下特点或用途:
- 基于NumPy,提供了矩阵运算
- 强大的分析结构化数据的工具集
- 提供数据清洗功能
(一)数据结构
1、Series
是带标签的一维数组,可存储整数、浮点数、字符串、Python 对象等类型的数据。轴标签统称为索引。调用 pd.Series
函数即可创建 Series,所以它有以下特点:
- 类似一维数组的对象
- 可通过list或者dict构建Series
- 由数据和索引组成(索引在左,数据在右;索引是自动创建的)
#通过list创建Series数据核结构 >>> ser_obj = pd.Series(range(5)) >>> type(ser_obj) <class 'pandas.core.series.Series'> >>> ser_obj 0 0 1 1 2 2 3 3 4 4 dtype: int64 >>> pd.Series([0,1,2,3,4]) 0 0 1 1 2 2 3 3 4 4 dtype: int64 #通过values和index方法获取数据和索引 >>> ser_obj.index RangeIndex(start=0, stop=5, step=1) #获取索引对象,可通过迭代获取每一个值 >>> index_obj = ser_obj.index >>> index_obj[0] 0 >>> values_obj = ser_obj.values >>> values_obj array([0, 1, 2, 3, 4], dtype=int64) #获取值组成的数组 >>> #通过head方法预览数据 >>> ser_obj.head() #所有数据 0 0 1 1 2 2 3 3 4 4 dtype: int64 >>> ser_obj.head(2) #前两行 0 0 1 1 #通过索引获取数据 >>> ser_obj[1] 1 >>> #通过字典构建Series >>> ser_obj = pd.Series({'a':1,'b':2}) >>> ser_obj a 1 b 2 #Series支持name属性 >>> ser_obj = pd.Series(np.random.randn(5),name='he') >>> ser_obj.name 'he'
2、DataFrame
DataFrame 是由多种类型的列构成的二维标签数据结构,类似于 Excel 、SQL 表,或 Series 对象构成的字典。DataFrame 是最常用的 Pandas 对象,与 Series 一样,DataFrame 支持多种类型的输入数据:
- 一维 ndarray、列表、字典、Series 字典
- 二维 numpy.ndarray
- SeriesDataFrame
所以,总的来说它具有以下特点:
- 类似多维数组/表格数据
- 每列数据可以是不同的类型
- 索引包括列索引和行索引
DataFrame 的构建:
#通过ndarray构建DataFrame >>> array = np.arange(12).reshape(3,4) >>> array array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> df_obj = pd.DataFrame(array) >>> df_obj.head() 0 1 2 3 0 0 1 2 3 1 4 5 6 7 #通过字典构建DataFrame >>> d = {'one':[1,2,3],'two':[4,5,6]} >>> df = pd.DataFrame(d) >>> df one two 0 1 4 1 2 5 2 3 6 >>> >>> d = {'one':[1,2,3],'two':[4,5,6]} >>> df = pd.DataFrame(d,index=['a','b','c']) >>> df one two a 1 4 b 2 5 c 3 6 >>> #通过Series构建DataFrame >>> d = {'one':pd.Series([1,2,3],index=['a','b','c']),'two':pd.Series([4,5,6],in dex=['a','b','c'])} >>> df = pd.DataFrame(d) >>> df one two a 1 4 b 2 5 c 3 6 >>>
操作DataFrame中的数据:
#通过列索引获取列数据(Series类型 ),df[col_idx] 或 df.col_idx >>> d = {'one':[1,2,3],'two':[4,5,6]} >>> df = pd.DataFrame(d) >>> df one two 0 1 4 1 2 5 2 3 6 >>> df['one'] 0 1 1 2 2 3 Name: one, dtype: int64 >>> type(df['one']) <class 'pandas.core.series.Series'> #增加列数据,类似dict添加key-value,df[new_col_idx] = data >>> df['three'] = [7,8,9] >>> df one two three 0 1 4 7 1 2 5 8 2 3 6 9 #删除列 del df[col_idx] >>> del df['three'] >>> df one two 0 1 4 1 2 5 2 3 6 >>>
索引对象Index:
#构建DataFrame >>> d = {'one':[1,2,3],'two':[4,5,6]} >>> df = pd.DataFrame(d) >>> df one two 0 1 4 1 2 5 2 3 6 #取出索引对象 >>> df.index RangeIndex(start=0, stop=3, step=1) >>> type(df.index) <class 'pandas.core.indexes.range.RangeIndex'> >>>
可以看出Pandas中的索引对象有以下特点:
- Series和DataFrame中的索引都是Index对象
- 不可变(immutable) (保证数据的安全性)
- 常见的Index对象的种类(Index,Int64Index,MultiIndex,DatetimeIndex)
(二)数据操作
1、索引操作
Pandas的索引可归纳为3种,分别为:.loc,标签索引;.iloc,位置索引;.ix,标签与位置混合索引(先按标签索引操作,然后再按位置索引操作)。值得注意的是DataFrame中的索引操作可按照NumPy中的ndarray进行操作。
位置索引不包含末尾的切片索引,但是标签索引包含末尾的切片索引。
-
Series索引操作
>>> import pandas as pd >>> ser_obj = pd.Series(range(5),index=['a','b','c','d','e']) >>> ser_obj.head() a 0 b 1 c 2 d 3 e 4 dtype: int64 #行索引 >>> ser_obj['b'] #标签索引 1 >>> ser_obj[1] #位置索引 1 #切片索引 >>> ser_obj['a':'c'] #标签索引 a 0 b 1 c 2 dtype: int64 >>> ser_obj[0:2] a 0 b 1 dtype: int64 #不连续索引 >>> ser_obj[[0,2]] a 0 c 2 dtype: int64 >>> ser_obj[['a','c']] a 0 c 2 dtype: int64 >>> #布尔索引,按照位置索引,将满足的位置的数据取出 >>> ser_bool = ser_obj > 2 >>> ser_bool a False b False c False d True e True dtype: bool >>> ser_obj[ser_bool] d 3 e 4 dtype: int64 >>>
-
DataFrame索引操作
>>> df_obj = pd.DataFrame(np.random.rand(3,4)) >>> df_obj 0 1 2 3 0 0.083639 0.773814 0.385009 0.067200 1 0.135069 0.286290 0.359994 0.204416 2 0.642119 0.830445 0.908530 0.483679 >>> df_obj = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d']) >>> df_obj a b c d 0 0.876338 0.753406 0.098060 0.896880 1 0.245380 0.769202 0.212327 0.296384 2 0.892388 0.739253 0.173457 0.996446 #列索引 >>> df_obj['a'] # 返回Series类型 0 0.876338 1 0.245380 2 0.892388 Name: a, dtype: float64 #不连续列索引 >>> df_obj[['a','c']] a c 0 0.876338 0.098060 1 0.245380 0.212327 2 0.892388 0.173457 >>>
-
三种索引方式
##############1、Series################# >>> ser_obj a 0 b 1 c 2 d 3 e 4 dtype: int64 >>> #(1)标签索引loc >>> ser_obj['b':'d'] b 1 c 2 d 3 dtype: int64 >>> ser_obj.loc['b':'d'] b 1 c 2 d 3 dtype: int64 #(2)位置索引iloc >>> ser_obj[1:3] b 1 c 2 dtype: int64 >>> ser_obj.iloc[1:3] b 1 c 2 dtype: int64 #(3)混合索引ix >>> ser_obj.ix[1:3] b 1 c 2 dtype: int64 >>> ser_obj.ix['b':'c'] b 1 c 2 dtype: int64 ##############2、DataFrame################# >>> df_obj a b c d 0 0.876338 0.753406 0.098060 0.896880 1 0.245380 0.769202 0.212327 0.296384 2 0.892388 0.739253 0.173457 0.996446 >>> #(1)标签索引loc >>> df_obj['a'] 0 0.876338 1 0.245380 2 0.892388 Name: a, dtype: float64 >>> df_obj.loc[0:2,'a'] 0 0.876338 1 0.245380 2 0.892388 Name: a, dtype: float64 >>> #(2)位置索引iloc >>> df_obj.iloc[0:2,0] 0 0.876338 1 0.245380 Name: a, dtype: float64 #(3)混合索引ix >>> df_obj.ix[0:2,0] #先按标签索引尝试操作,然后再按位置索引尝试操作 0 0.876338 1 0.245380 2 0.892388 Name: a, dtype: float64
2、运算与对齐
- 按索引对齐运算,没对齐的位置补NaN(Series 按行索引对齐;DataFrame按行,列索引对齐)
- 填充未对齐的数据进行运算(使用add, sub, div, mul;同时通过fill_value指定填充值)
- 填充NaN(通过fillna进行填充)
###############按照索引对齐运算############ #Series对齐运算 >>> s1 = pd.Series(np.arange(10)) >>> s1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 dtype: int32 >>> s2 = pd.Series(range(5)) >>> s2 0 0 1 1 2 2 3 3 4 4 dtype: int64 >>> s1+s2 #进行求和运算 0 0.0 1 2.0 2 4.0 3 6.0 4 8.0 5 NaN 6 NaN 7 NaN 8 NaN 9 NaN dtype: float64 >>> #DataFrame对齐运算 >>> df1 = pd.DataFrame(np.random.rand(3,2),columns=['a','b']) >>> df1 a b 0 0.312066 0.913311 1 0.562698 0.055995 2 0.917202 0.876010 >>> df2 = pd.DataFrame(np.arange(12).reshape(2,6),columns=['a','b','c','d','e',' f']) >>> df2 a b c d e f 0 0 1 2 3 4 5 1 6 7 8 9 10 11 >>> df1+df2 #进行求和运算 a b c d e f 0 0.010841 1.715210 NaN NaN NaN NaN 1 6.967361 7.151983 NaN NaN NaN NaN 2 NaN NaN NaN NaN NaN NaN >>> ###############填充未对齐的数据进行运算## ###Series运算 >>> s1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 dtype: int32 >>> s2 0 0 1 1 2 2 3 3 4 4 dtype: int64 >>> s1.add(s2,fill_value=1) 0 0.0 1 2.0 2 4.0 3 6.0 4 8.0 5 6.0 6 7.0 7 8.0 8 9.0 9 10.0 dtype: float64 >>> ##DataFrame运算 >>> df1 a b 0 0.010841 0.715210 1 0.967361 0.151983 2 0.652059 0.857662 >>> df2 a b c d e f 0 0 1 2 3 4 5 1 6 7 8 9 10 11 >>> df1.div(df2,fill_value=1) a b c d e f 0 inf 0.715210 0.500 0.333333 0.25 0.200000 1 0.161227 0.021712 0.125 0.111111 0.10 0.090909 2 0.652059 0.857662 NaN NaN NaN NaN ###############填充NaN## >>> s3=s1+s2 >>> s3 0 0.0 1 2.0 2 4.0 3 6.0 4 8.0 5 NaN 6 NaN 7 NaN 8 NaN 9 NaN dtype: float64 >>> s3.fillna(1) #用1进行填充 0 0.0 1 2.0 2 4.0 3 6.0 4 8.0 5 1.0 6 1.0 7 1.0 8 1.0 9 1.0 dtype: float64 >>>
3、函数应用
-
使用NumPy的ufunc函数
#使用NumPy的ufunc函数 >>> df = pd.DataFrame(np.arange(12).reshape(6,2)) >>> df 0 1 0 0 1 1 2 3 2 4 5 3 6 7 4 8 9 5 10 11 >>> np.cos(df) 0 1 0 1.000000 0.540302 1 -0.416147 -0.989992 2 -0.653644 0.283662 3 0.960170 0.753902 4 -0.145500 -0.911130 5 -0.839072 0.004426 >>>
-
通过apply将函数应用到行或列上(注意指定轴的方向,默认axis=0)
>>> df 0 1 0 0 1 1 2 3 2 4 5 3 6 7 4 8 9 5 10 11 >>> df.apply(lambda x : x.max()) 0 10 1 11 dtype: int64 >>> df.apply(lambda x : x.max(),axis=1) #指定轴的方向 0 1 1 3 2 5 3 7 4 9 5 11 dtype: int64 >>>
-
通过applymap将函数应用到每个数据上
>>> df 0 1 0 0 1 1 2 3 2 4 5 3 6 7 4 8 9 5 10 11 >>> df.applymap(lambda x : x if x%2 ==0 else 0) #应用到每一个元素 0 1 0 0 0 1 2 0 2 4 0 3 6 0 4 8 0 5 10 0 >>>
4、排序
-
索引排序(sort_index)
在对DataFrame操作时注意轴的方向
########Series类型######## >>> ser_obj = pd.Series(np.arange(10),index=np.random.randint(10,size=10)) >>> ser_obj 5 0 0 1 1 2 5 3 8 4 6 5 5 6 3 7 6 8 6 9 dtype: int32 >>> ser_obj.sort_index() 0 1 1 2 3 7 5 0 5 3 5 6 6 5 6 8 6 9 8 4 dtype: int32 >>> ########DataFrame类型######## >>> df = pd.DataFrame(np.random.rand(5,6),index=np.random.randint(5,size=5),co mns=np.random.randint(6,size=6)) >>> df 1 3 5 4 2 1 1 0.606201 0.771622 0.883784 0.014313 0.841963 0.917798 1 0.532707 0.001340 0.098712 0.412165 0.593807 0.455049 0 0.920531 0.470740 0.735235 0.400583 0.440331 0.168443 1 0.823637 0.436724 0.180092 0.313742 0.979541 0.543043 0 0.905565 0.835106 0.802815 0.275947 0.051905 0.710654 >>> df.sort_index() 1 3 5 4 2 1 0 0.920531 0.470740 0.735235 0.400583 0.440331 0.168443 0 0.905565 0.835106 0.802815 0.275947 0.051905 0.710654 1 0.606201 0.771622 0.883784 0.014313 0.841963 0.917798 1 0.532707 0.001340 0.098712 0.412165 0.593807 0.455049 1 0.823637 0.436724 0.180092 0.313742 0.979541 0.543043 >>> df.sort_index(axis=1) #指定轴方向 1 1 2 3 4 5 1 0.606201 0.917798 0.841963 0.771622 0.014313 0.883784 1 0.532707 0.455049 0.593807 0.001340 0.412165 0.098712 0 0.920531 0.168443 0.440331 0.470740 0.400583 0.735235 1 0.823637 0.543043 0.979541 0.436724 0.313742 0.180092 0 0.905565 0.710654 0.051905 0.835106 0.275947 0.802815 >>> >>> df.sort_index(axis=1,ascending=False) #索引降序 5 4 3 2 1 1 1 0.883784 0.014313 0.771622 0.841963 0.606201 0.917798 1 0.098712 0.412165 0.001340 0.593807 0.532707 0.455049 0 0.735235 0.400583 0.470740 0.440331 0.920531 0.168443 1 0.180092 0.313742 0.436724 0.979541 0.823637 0.543043 0 0.802815 0.275947 0.835106 0.051905 0.905565 0.710654 >>>
-
值排序(sort_values)
sort_values(by=‘label’),其中参数by是按照标签名进行排序
>>> df 1 3 5 4 2 1 1 0.606201 0.771622 0.883784 0.014313 0.841963 0.917798 1 0.532707 0.001340 0.098712 0.412165 0.593807 0.455049 0 0.920531 0.470740 0.735235 0.400583 0.440331 0.168443 1 0.823637 0.436724 0.180092 0.313742 0.979541 0.543043 0 0.905565 0.835106 0.802815 0.275947 0.051905 0.710654 >>> df.sort_values(by=2) #按照label为2进行排序 1 3 5 4 2 1 0 0.905565 0.835106 0.802815 0.275947 0.051905 0.710654 0 0.920531 0.470740 0.735235 0.400583 0.440331 0.168443 1 0.532707 0.001340 0.098712 0.412165 0.593807 0.455049 1 0.606201 0.771622 0.883784 0.014313 0.841963 0.917798 1 0.823637 0.436724 0.180092 0.313742 0.979541 0.543043 >>>
5、处理缺失数据
-
判断是否存在缺失值
可通过ser.isnull()、df.isnull()判断是否存在缺失数据
#判断Series中是否有缺失数据 >>> ser = pd.Series([1,np.nan,2,3]) >>> ser 0 1.0 1 NaN 2 2.0 3 3.0 dtype: float64 >>> ser.isnull() 0 False 1 True 2 False 3 False dtype: bool >>> #判断DataFrame中是否有缺失数据 >>> df = pd.DataFrame([np.random.randint(3,size=3),[1,np.nan,2],[3,np.nan,7]],in dex=['a','b','c']) >>> df 0 1 2 a 0 1.0 1 b 1 NaN 2 c 3 NaN 7 >>> df.isnull() 0 1 2 a False False False b False True False c False True False >>>
-
丢弃缺失数据(dropna)
>>> df.dropna <bound method DataFrame.dropna of 0 1 2 a 0 1.0 1 b 1 NaN 2 c 3 NaN 7> >>> df.dropna() 0 1 2 a 0 1.0 1 >>> df.dropna(axis=1) #凡是某一行中有缺失的数据的列丢弃 0 2 a 0 1 b 1 2 c 3 7 >>> df.dropna(axis=0) #凡是某一列中有缺失的数据的行丢弃 0 1 2 a 0 1.0 1 >>>
-
填充缺失数据(fillna)
>>> df 0 1 2 a 0 1.0 1 b 1 NaN 2 c 3 NaN 7 >>> df.fillna(10) 0 1 2 a 0 1.0 1 b 1 10.0 2 c 3 10.0 7
二、Pandas进阶
(一)统计计算和描述
方法 |
说明 |
count |
非NA值得数量 |
describe |
针对Series或DataFrame列计算汇总统计 |
min、max |
计算最小值和最大值 |
argmin、argmax |
计算能够获取到的最小值和最大值的索引位置(整数) |
idxmin、idmax |
计算能够获取到的最小值和最大值的索引值 |
quantile |
计算样本的分位数(0到1) |
sum |
值得总和 |
mean |
值得平均数 |
median |
值的算术中位数 |
mad |
根据平均值计算平均绝对离差 |
var |
样本值得方差 |
std |
样本值得标准差 |
skew |
样本值的偏度(三阶矩) |
kurt |
样本值的峰度(四阶矩) |
cumsum |
样本值得累计和 |
cummin、cummax |
样本值得累计最大值和累积最小值 |
cumprod |
样本值得累计积 |
diff |
计算一阶差分(一般用于时间序列) |
pct_change |
计算百分数变化 |
1、常用的统计计算
- sum, mean, max, min
- axis=0 按列统计,axis=1按行统计
- skipna 排除缺失值, 默认为True
- idmax, idmin, cumsum
>>> df_obj = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d']) >>> df_obj a b c d 0 0.123562 0.201605 0.823654 0.419873 1 0.402363 0.431577 0.134377 0.898711 2 0.019123 0.728064 0.548855 0.035298 >>> df_obj.sum() a 0.545049 b 1.361245 c 1.506887 d 1.353882 dtype: float64 >>> df_obj.max() a 0.402363 b 0.728064 c 0.823654 d 0.898711 dtype: float64 >>> df_obj.min() a 0.019123 b 0.201605 c 0.134377 d 0.035298 dtype: float64 >>> df_obj.mean() a 0.181683 b 0.453748 c 0.502296 d 0.451294 dtype: float64 >>> df_obj.min(axis=1) 0 0.123562 1 0.134377 2 0.019123 dtype: float64 >>>
2、统计描述
- describe 产生多个统计数据
>>> df_obj = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d']) >>> df_obj a b c d 0 0.494064 0.188160 0.767935 0.939915 1 0.094445 0.183256 0.683518 0.058220 2 0.380939 0.350230 0.645671 0.190707 >>> df_obj.describe() a b c d count 3.000000 3.000000 3.000000 3.000000 mean 0.323149 0.240549 0.699041 0.396281 std 0.205982 0.095019 0.062593 0.475439 min 0.094445 0.183256 0.645671 0.058220 25% 0.237692 0.185708 0.664594 0.124464 50% 0.380939 0.188160 0.683518 0.190707 75% 0.437502 0.269195 0.725727 0.565311 max 0.494064 0.350230 0.767935 0.939915 >>>
(二)层级索引
|
|
0 |
1 |
A |
one |
3.000000 |
3.000000 |
two |
0.240549 |
0.323149 |
|
B |
one |
0.205982 |
0.095019 |
two |
0.094445 |
0.183256 |
- MultiIndex对象
- 选取子集(外层选取 ser_obj[‘outer_label’];内层选取 ser_obj[:, ‘inner_label’])
- 常用于分组操作、透视表的生成等
- 交换分层顺序(swaplevel())
- 排序分层(sortlevel())
#创建MultiIndex对象 >>> ser_obj = pd.Series(np.random.randint(4,size=4),index=[['A','A','B','B'],['o ne','two','one','two']]) >>> ser_obj A one 2 two 2 B one 2 two 2 dtype: int32 #选取子集 >>> ser_obj['A'] #外层选取 one 2 two 2 dtype: int32 >>> ser_obj[:,'two'] #内层选取 A 2 B 2 dtype: int32 >>> #交换分层 >>> ser_obj.swaplevel() one A 2 two A 2 one B 2 two B 2 dtype: int32 >>> #交换并排序分层 >>> ser_obj.swaplevel().sortlevel() __main__:1: FutureWarning: sortlevel is deprecated, use sort_index(level=...) one A 2 B 2 two A 2 B 2 dtype: int32
(三)分组(groupby)
对数据集进行分组,然后对每组进行统计分析,分组步骤如下:
- 拆分(split):进行分组的根据
- 应用(apply):每个分组运行的计算规则
- 合并(combine):把每个分组的计算结果合并起来
1、GroupBy对象属性
- GroupBy对象:DataFrameGroupBy,SeriesGroupBy
- GroupBy对象没有进行实际运算,只是包含分组的中间数据
- GroupBy对象进行分组运算/多重分组运算,如mean(),sum();注意非数值数据不进行分组运算
- size() 返回每个分组的元素个数
源数据:
>>> import pandas as pd >>> import numpy as np >>> dict_obj = {'k1':['a','b','c','a','b'],'d1':np.random.randn(5)} >>> df_obj = pd.DataFrame(dict_obj) >>> df_obj d1 k1 0 -0.716924 a 1 -1.533428 b 2 1.452550 c 3 0.586476 a 4 0.586688 b >>>
dataframe根据k1进行分组:
#DataFrameGroupBy 对象 >>> df_obj.groupby('k1') <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000000004CEFC18> >>> df_obj.groupby('k1') <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000000004CEFD30> >>> type(df_obj.groupby('k1')) <class 'pandas.core.groupby.groupby.DataFrameGroupBy'>
dataframe某一列根据k1进行分组:
#SeriesGroupBy对象 >>> df_obj d1 k1 0 -0.716924 a 1 -1.533428 b 2 1.452550 c 3 0.586476 a 4 0.586688 b >>> df_obj['d1'].groupby(df_obj['k1']) <pandas.core.groupby.groupby.SeriesGroupBy object at 0x0000000004D01710> >>> type(df_obj['d1'].groupby(df_obj['k1'])) <class 'pandas.core.groupby.groupby.SeriesGroupBy'> >>>
分组运算:
>>> df_obj d1 k1 0 -0.716924 a 1 -1.533428 b 2 1.452550 c 3 0.586476 a 4 0.586688 b >>> df_obj.groupby('k1') <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000000004CF94A8> #分组求均值 >>> df_obj.groupby('k1').mean() d1 k1 a -0.065224 b -0.473370 c 1.452550 #分组求和 >>> df_obj.groupby('k1').sum() d1 k1 a -0.130448 b -0.946740 c 1.452550 >>> #分组中的每一组元素个数 >>> df_obj.groupby('k1').size() k1 a 2 b 2 c 1 dtype: int64 >>>
2、分组的依据
- 按列名分组(obj.groupby(‘label’))
- 按列名多层分组(obj.groupby([‘label1’, ‘label2’])->多层dataframe)
- 按自定义的key分组(obj.groupby(self_def_key);自定义的key可为列表或多层列表)
- unstack可以将多层索引的结果转换成单层的dataframe
- 其它分组依据(按列分组、字典分组、函数分组,函数传入的参数为行索引或列索引、索引级别)
>>> df_obj d1 k1 0 -0.716924 a 1 -1.533428 b 2 1.452550 c 3 0.586476 a 4 0.586688 b #按列名分组 >>> df_obj.groupby('k1') <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000000004CF94A8> #按列分组 >>> df_obj.dtypes d1 float64 k1 object dtype: object >>> #按数据类型分组 >>> df_obj.dtypes d1 float64 k1 object dtype: object >>> df_obj.groupby(df_obj.dtypes,axis=1) <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000000004CEF748> >>> df_obj.groupby(df_obj.dtypes,axis=1).size() float64 1 object 1 dtype: int64
3、GroupBy对象操作
-
GroupBy对象支持迭代操作
每次迭代返回一个元组 (group_name, group_data),可用于分组数据的具体运算。
>>> df_obj d1 k1 0 -0.716924 a 1 -1.533428 b 2 1.452550 c 3 0.586476 a 4 0.586688 b >>> grouped1 = df_obj.groupby('k1') >>> grouped1 <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000000004CF9BE0> >>> for group_name,group_data in grouped1: ... print(group_name) ... print(group_data) ... a d1 k1 0 -0.716924 a 3 0.586476 a b d1 k1 1 -1.533428 b 4 0.586688 b c d1 k1 2 1.45255 c >>>
-
GroupBy对象可以转换成列表或字典
>>> df_obj d1 k1 0 -0.716924 a 1 -1.533428 b 2 1.452550 c 3 0.586476 a 4 0.586688 b >>> grouped1 = df_obj.groupby('k1') >>> grouped1 <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000000004CF9BE0> >>> list(grouped1) #转成列表 [('a', d1 k1 0 -0.716924 a 3 0.586476 a), ('b', d1 k1 1 -1.533428 b 4 0.586688 b), ('c', d1 k1 2 1.45255 c)] >>> >>> dict(list(grouped1)) #转成字典 {'b': d1 k1 1 -1.533428 b 4 0.586688 b, 'c': d1 k1 2 1.45255 c, 'a': d1 k1 0 -0.716924 a 3 0.586476 a} >>>
(四)聚合(aggregation)
1、常用聚合函数
聚合常用于对分组后的数据进行计算,常见的聚合函数如下:
函数名 |
说明 |
count |
分组中非NA值得数量 |
sum |
非NA值的和 |
mean |
非NA值得平均值 |
median |
非NA值得算术中位数 |
std、var |
无偏(分母为n-1)标准差和方差 |
min、max |
非NA值得最小值和最大值 |
Prod |
非NA值得积 |
first、last |
第一个和最后一个非NA值 |
#内置聚合函数 >>> import pandas as pd >>> import numpy as np >>> dict_obj = {'k1':['a','b','c','a','b'],'d1':np.random.randn(5)} >>> df_obj = pd.DataFrame(dict_obj) >>> df_obj d1 k1 0 1.688729 a 1 -0.187755 b 2 0.900189 c 3 -0.105254 a 4 0.133984 b >>> df_obj.groupby('k1') #以k1进行分组 <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x000000000470C8D0> >>> df_obj.groupby('k1').sum() #求和 d1 k1 a 1.583474 b -0.053770 c 0.900189 >>> df_obj.groupby('k1').mean() #均值 d1 k1 a 0.791737 b -0.026885 c 0.900189 >>> df_obj.groupby('k1').describe() d1 ... count mean std ... 50% 75% max k1 ... a 2.0 0.791737 1.268538 ... 0.791737 1.240233 1.688729 b 2.0 -0.026885 0.227504 ... -0.026885 0.053550 0.133984 c 1.0 0.900189 NaN ... 0.900189 0.900189 0.900189 [3 rows x 8 columns] >>> df_obj.groupby('k1').first() d1 k1 a 1.688729 b -0.187755 c 0.900189 >>> df_obj.groupby('k1').last() d1 k1 a -0.105254 b 0.133984 c 0.900189 >>> df_obj.groupby('k1').prod() d1 k1 a -0.177746 b -0.025156 c 0.900189 >>>
2、自定义聚合函数
当然还可以自定义聚合函数,传入agg方法中:
- grouped.agg(func)
- func的参数为groupby索引对应的记录
#源数据 >>> dict_obj = {'k1':['a','b','c','a','b'],'d1':np.random.randn(5)} >>> df_obj = pd.DataFrame(dict_obj) >>> df_obj d1 k1 0 1.688729 a 1 -0.187755 b 2 0.900189 c 3 -0.105254 a 4 0.133984 b #自定义聚合函数,对每一组中的数据进行处理,注意传入的是每一组数据 >>> def peak_range(df): #对每一组数据中的最大值和最小值求差值,df为索引对应的记录 ... return df.max()-df.min() ... >>> df_obj.groupby('k1').agg(peak_range) d1 k1 a 1.793983 b 0.321739 c 0.000000 >>> #另一种直接使用lambda函数 >>> df_obj.groupby('k1').agg(lambda df : df.max() - df.min())
3、应用多个聚合函数
- 同时应用多个函数进行聚合操作,使用函数列表
- 对不同的列分别作用不同的聚合函数,使用dict
#使用函数列表 >>> df_obj d1 k1 0 1.688729 a 1 -0.187755 b 2 0.900189 c 3 -0.105254 a 4 0.133984 b >>> df_obj.groupby('k1').agg(['mean','count',peak_range]) d1 mean count peak_range k1 a 0.791737 2 1.793983 b -0.026885 2 0.321739 c 0.900189 1 0.000000 >>> >>> df_obj.groupby('k1').agg(['mean','count',('range',peak_range)]) #通过元祖提供别名 d1 mean count range k1 a 0.791737 2 1.793983 b -0.026885 2 0.321739 c 0.900189 1 0.000000 >>> #通过字典作用于不同列的函数 >>> dict_mapping = {'d1':'sum'} >>> df_obj.groupby('k1').agg(dict_mapping) d1 k1 a 1.583474 b -0.053770 c 0.900189 >>> >>> dict_mapping = {'d1':['sum','max','min']} >>> df_obj.groupby('k1').agg(dict_mapping) d1 sum max min k1 a 1.583474 1.688729 -0.105254 b -0.053770 0.133984 -0.187755 c 0.900189 0.900189 0.900189 >>>
4、分组聚合运算后保持shape
-
源数据
>>> df_obj d1 k1 0 1.688729 a 1 -0.187755 b 2 0.900189 c 3 -0.105254 a 4 0.133984 b >>> df_obj.groupby('k1').agg('sum').add_prefix('func_') func_d1 k1 a 1.583474 b -0.053770 c 0.900189 >>>
-
方法一 merge外连接
>>> k1_func = df_obj.groupby('k1').agg('sum').add_prefix('func_') >>> pd.merge(df_obj,k1_func,left_on='k1',right_index=True) d1 k1 func_d1 0 1.688729 a 1.583474 3 -0.105254 a 1.583474 1 -0.187755 b -0.053770 4 0.133984 b -0.053770 2 0.900189 c 0.900189
-
方法二 transform
>>> k1_func = df_obj.groupby('k1').transform(np.sum).add_prefix('func_') >>> df_obj[k1_func.columns] = k1_func >>> df_obj d1 k1 func_d1 0 1.688729 a 1.583474 1 -0.187755 b -0.053770 2 0.900189 c 0.900189 3 -0.105254 a 1.583474 4 0.133984 b -0.053770 >>>
另外,tansform也可以传入自定义函数:
>>> df_obj d1 k1 func_d1 0 1.688729 a 1.583474 1 -0.187755 b -0.053770 2 0.900189 c 0.900189 3 -0.105254 a 1.583474 4 0.133984 b -0.053770 #自定义函数 >>> def peak_range(df): ... return df.max()-df.min() ... >>> df_obj.groupby('k1').transform(peak_range) d1 func_d1 0 1.793983 0.0 1 0.321739 0.0 2 0.000000 0.0 3 1.793983 0.0 4 0.321739 0.0
三、Pandas高级
(一)数据清洗
数据清洗是将重复、多余的数据筛选清除,将缺失的数据补充完整,将错误的数据纠正或者删除,最后整理成为可以进一步加工、使用的数据。
数据清洗的步骤:
- 分析数据
- 缺失值处理
- 异常值处理
- 去重处理
- 噪音数据处理
常见使用的方法:
- 填充缺失值(pd.fillna())
- 删除缺失值(pd.dropna())
(二)数据连接
根据单个或多个键将不同DataFrame的行连接起来,可使用pd.merge()方法来实现,该方法默认的是将不同DataFrame重叠列的列名作为”外键“进行连接:
- on显示指定“外键”
- left_on,左侧数据的“外键”
- right_on,右侧数据的“外键”
该方法默认的是“内连接”(inner),即结果中的键是交集。
pd.merge()方法参数说明:
参数 |
说明 |
left |
参与合并的左侧DataFrame |
right |
参与合并的右侧DataFrame |
how |
“inner”、”outer”、”left”、”right”,默认为”inner” |
on |
用于连接的列名。必须存在于左右两个DataFrame对象中,默认为left和right列名的交集作为连接键。 |
left_on |
左侧DataFrame用作连接键的列 |
right_on |
右侧DataFrame用作连接键的列 |
left_index |
将左侧的行索引用作其连接键 |
right_index |
将右侧的行索引用作其连接键 |
sort |
根据连接键对合并后的数据进行排序,默认为True |
suffixes |
字符串值元祖,用于追加到重叠列名的末尾,默认为(”_x”,”_y”)。例如,如果左右两个DataFrame对象都有”data”,则结果就会出现”data_x”和“data_y” |
copy |
设置为False,可以避免将数据复制到结果数据结构中,默认是复制。 |
1、默认的方式重叠列连接
>>> import pandas as pd >>> import numpy as np >>> df_obj1 = pd.DataFrame({'k':['a','b','a','c','a','b'],'d1':np.arange(10,16)} ) >>> df_obj1 d1 k 0 10 a 1 11 b 2 12 a 3 13 c 4 14 a 5 15 b >>> df_obj2 = pd.DataFrame({'k':['a','b','a','b'],'d1':np.random.randint(0,15,4) }) >>> df_obj2 d1 k 0 13 a 1 14 b 2 7 a 3 10 b # 默认将重叠列的列名作为“外键”进行连接 >>> pd.merge(df_obj1,df_obj2) d1 k d2 0 10 a 14 1 10 a 4 2 12 a 14 3 12 a 4 4 14 a 14 5 14 a 4 6 11 b 10 7 11 b 9 8 15 b 10 9 15 b 9 #指定连接的外键 >>> pd.merge(df_obj1,df_obj2,on='k') d1 k d2 0 10 a 14 1 10 a 4 2 12 a 14 3 12 a 4 4 14 a 14 5 14 a 4 6 11 b 10 7 11 b 9 8 15 b 10 9 15 b 9
2、外连接、左连接、右连接
>>> df_obj1 d1 k 0 10 a 1 11 b 2 12 a 3 13 c 4 14 a 5 15 b >>> df_obj1=df_obj1.rename(columns={'k':'k1'}) # 更改列名 >>> df_obj1 d1 k1 0 10 a 1 11 b 2 12 a 3 13 c 4 14 a 5 15 b >>> df_obj2 d2 k 0 14 a 1 10 b 2 4 a 3 9 b >>> df_obj2=df_obj2.rename(columns={'k':'k2'}) # 更改列名 >>> df_obj2 d2 k2 0 14 a 1 10 b 2 4 a 3 9 b >>> pd.merge(df_obj1,df_obj2,left_on='k1',right_on='k2') d1 k1 d2 k2 0 10 a 14 a 1 10 a 4 a 2 12 a 14 a 3 12 a 4 a 4 14 a 14 a 5 14 a 4 a 6 11 b 10 b 7 11 b 9 b 8 15 b 10 b 9 15 b 9 b >>> #外连接 >>> pd.merge(df_obj1, df_obj2, left_on='k1', right_on='k2', how='outer') d1 k1 d2 k2 0 10 a 14.0 a 1 10 a 4.0 a 2 12 a 14.0 a 3 12 a 4.0 a 4 14 a 14.0 a 5 14 a 4.0 a 6 11 b 10.0 b 7 11 b 9.0 b 8 15 b 10.0 b 9 15 b 9.0 b 10 13 c NaN NaN #左连接 >>> pd.merge(df_obj1, df_obj2, left_on='k1', right_on='k2', how='left') d1 k1 d2 k2 0 10 a 14.0 a 1 10 a 4.0 a 2 11 b 10.0 b 3 11 b 9.0 b 4 12 a 14.0 a 5 12 a 4.0 a 6 13 c NaN NaN 7 14 a 14.0 a 8 14 a 4.0 a 9 15 b 10.0 b 10 15 b 9.0 b #右连接 >>> pd.merge(df_obj1, df_obj2, left_on='k1', right_on='k2', how='right') d1 k1 d2 k2 0 10 a 14 a 1 12 a 14 a 2 14 a 14 a 3 10 a 4 a 4 12 a 4 a 5 14 a 4 a 6 11 b 10 b 7 15 b 10 b 8 11 b 9 b 9 15 b 9 b >>>
3、处理重复列名
>>> df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], ... 'data' : np.random.randint(0,10,7)}) >>> >>> df_obj1 data key 0 1 b 1 5 b 2 8 a 3 3 c 4 3 a 5 0 a 6 9 b >>> df_obj2 = pd.DataFrame({'key': ['a', 'b', 'd'], ... 'data' : np.random.randint(0,10,3)}) >>> >>> df_obj2 data key 0 1 a 1 4 b 2 4 d #处理列名相同使用suffixes参数 >>> pd.merge(df_obj1,df_obj2,on='key',suffixes=('_left','_right')) data_left key data_right 0 1 b 4 1 5 b 4 2 9 b 4 3 8 a 1 4 3 a 1 5 0 a 1 >>>
(三)数据合并
沿轴方向将多个对象合并到一起,使用pd.concat()方法:
- 注意指定轴方向,默认axis=0
- join指定合并方式,默认为outer
- Series合并时查看行索引
- DataFrame合并时同时查看行索引和列索引
1、NumPy中的concatenate
#numpy中的合并concatenate >>> import numpy as np >>> import pandas as pd >>> arr1 = np.random.randint(0,10,(2,5)) >>> arr2 = np.random.randint(0,10,(3,5)) >>> arr1 array([[6, 4, 0, 5, 4], [8, 9, 4, 1, 9]]) >>> arr2 array([[0, 5, 5, 2, 5], [4, 2, 2, 5, 6], [9, 3, 3, 8, 4]]) >>> np.concatenate([arr1,arr2]) array([[6, 4, 0, 5, 4], [8, 9, 4, 1, 9], [0, 5, 5, 2, 5], [4, 2, 2, 5, 6], [9, 3, 3, 8, 4]]) >>>
2、Series中的concat
#1、索引不重复 >>> ser_obj1 = pd.Series(np.random.randint(0,10,5),index=range(5)) >>> ser_obj2 = pd.Series(np.random.randint(0,10,3),index=range(5,8)) >>> ser_obj1 0 0 1 1 2 2 3 9 4 5 dtype: int32 >>> ser_obj2 5 0 6 8 7 0 dtype: int32 #进行合并 >>> pd.concat([ser_obj1,ser_obj2]) 0 0 1 1 2 2 3 9 4 5 5 0 6 8 7 0 dtype: int32 >>> #axis=1 >>> pd.concat([ser_obj1,ser_obj2],axis=1) 0 1 0 0.0 NaN 1 1.0 NaN 2 2.0 NaN 3 9.0 NaN 4 5.0 NaN 5 NaN 0.0 6 NaN 8.0 7 NaN 0.0 >>> #2、索引有重复的 >>> ser_obj1 = pd.Series(np.random.randint(0,10,5),index=range(5)) >>> ser_obj2 = pd.Series(np.random.randint(0,10,3),index=range(3)) >>> ser_obj1 0 0 1 3 2 0 3 2 4 0 dtype: int32 >>> ser_obj2 0 2 1 0 2 1 dtype: int32 >>> pd.concat([ser_obj1,ser_obj2]) 0 0 1 3 2 0 3 2 4 0 0 2 1 0 2 1 dtype: int32 >>> >>> pd.concat([ser_obj1,ser_obj2],axis=1,join='inner') #axis方向 0 1 0 0 2 1 3 0 2 0 1 >>>
3、DataFrame中的concat
>>> df_obj1 = pd.DataFrame(np.random.randint(0,10,(3,4)),index=['a','b','c'],col umns=['A','B','C','D']) >>> df_obj2 = pd.DataFrame(np.random.randint(0,10,(2,4)),index=['a','b'],columns =['E','F','G','H']) >>> df_obj1 A B C D a 1 4 7 3 b 2 7 5 6 c 9 4 7 3 >>> df_obj2 E F G H a 5 6 6 5 b 3 3 1 5 >>> pd.concat([df_obj1,df_obj2]) A B C D E F G H a 1.0 4.0 7.0 3.0 NaN NaN NaN NaN b 2.0 7.0 5.0 6.0 NaN NaN NaN NaN c 9.0 4.0 7.0 3.0 NaN NaN NaN NaN a NaN NaN NaN NaN 5.0 6.0 6.0 5.0 b NaN NaN NaN NaN 3.0 3.0 1.0 5.0 >>> >>> pd.concat([df_obj1,df_obj2],axis=1) #指定轴方向 A B C D E F G H a 1 4 7 3 5.0 6.0 6.0 5.0 b 2 7 5 6 3.0 3.0 1.0 5.0 c 9 4 7 3 NaN NaN NaN NaN >>>
(四)数据重构
1、stack
- 将列索引旋转为行索引
- 完成层级索引
- DataFrame->Series
#stack将DataFrame转成Series >>> import numpy as np >>> import pandas as pd >>> df_obj = pd.DataFrame(np.random.randint(0,10,(3,4)),columns=['a','b','c','d' ]) >>> df_obj a b c d 0 1 5 8 8 1 5 5 0 1 2 6 5 5 3 >>> stacked = df_obj.stack() >>> stacked 0 a 1 b 5 c 8 d 8 1 a 5 b 5 c 0 d 1 2 a 6 b 5 c 5 d 3 dtype: int32 >>> type(stacked) <class 'pandas.core.series.Series'> >>> type(stacked.index) <class 'pandas.core.indexes.multi.MultiIndex'> >>>
2、unstack
- 将层级索引展开
- Series->DataFrame
- 默认操作内层索引,即level=-1
>>> stacked 0 a 1 b 5 c 8 d 8 1 a 5 b 5 c 0 d 1 2 a 6 b 5 c 5 d 3 dtype: int32 >>> stacked .unstack() ## 默认操作内层索引 a b c d 0 1 5 8 8 1 5 5 0 1 2 6 5 5 3 >>> stacked .unstack(level=0) # 通过level指定操作索引的级别 0 1 2 a 1 5 6 b 5 5 5 c 8 0 5 d 8 1 3 >>>
(五)数据转换
1、处理重复数据
- duplicated() 返回布尔型Series表示每行是否为重复行
- drop_duplicates() 过滤重复行(默认判断全部列;可指定按某些列判断)
>>> df_obj = pd.DataFrame({'d1':['a']*3+['b']*5,'d2':np.random.randint(0,10,8)}) >>> df_obj d1 d2 0 a 1 1 a 1 2 a 6 3 b 0 4 b 6 5 b 3 6 b 4 7 b 3 >>> df_obj.duplicated() #判断重复行,重复行为True 0 False 1 True 2 False 3 False 4 False 5 False 6 False 7 True dtype: bool >>> df_obj.drop_duplicates() #将重复行去除 d1 d2 0 a 1 2 a 6 3 b 0 4 b 6 5 b 3 6 b 4 >>> >>> df_obj.drop_duplicates('d2') d1 d2 0 a 1 2 a 6 3 b 0 5 b 3 6 b 4 >>>
2、map
- Series根据map传入的函数对每行或每列进行转换
>>> ser_obj = pd.Series(np.random.randint(0,15,10)) >>> ser_obj 0 10 1 8 2 13 3 14 4 12 5 7 6 6 7 14 8 4 9 8 dtype: int32 >>> ser_obj.map(lambda x:x**3) 0 1000 1 512 2 2197 3 2744 4 1728 5 343 6 216 7 2744 8 64 9 512 dtype: int64 >>> ser_obj.map(lambda x:x**3)
3、数据替换(replace)
#Series中的替换 >>> ser_obj = pd.Series(np.random.randint(0,15,10)) >>> ser_obj 0 1 1 10 2 10 3 9 4 12 5 11 6 8 7 7 8 8 9 2 dtype: int32 #单值替换 >>> ser_obj.replace(10,100) #将10这个数替换成100 0 1 1 100 2 100 3 9 4 12 5 11 6 8 7 7 8 8 9 2 dtype: int32 #多值替换 >>> ser_obj 0 1 1 10 2 10 3 9 4 12 5 11 6 8 7 7 8 8 9 2 >>> ser_obj.replace([1,9],-100) #将1和9替换成-100 0 -100 1 10 2 10 3 -100 4 12 5 11 6 8 7 7 8 8 9 2 dtype: int32 >>> ser_obj.replace([1,9],[-100,-200]) #将1替换成-100,将9替换成-200 0 -100 1 10 2 10 3 -200 4 12 5 11 6 8 7 7 8 8 9 2 dtype: int64 >>>