python3 科学计算之pandas入门(四)


一.汇总和计算描述统计

pandas对象拥有一组常用的数学和统计方法。它们大部分属于约简和汇总统计,用于从Series中提取单个值(如sum或mean)或从DataFrame的行或列中提取一个Series。跟对应的Numpy数组方法相比,它们都是基于没有缺失数据的假设而构建的。接下来看一个简单的DataFrame:

In [1]: import numpy as np

In [2]: from pandas import Series,DataFrame

In [3]: df=DataFrame([[1.4,np.nan],[8.4,-3.5],[np.nan,np.nan],[0.65,-2.3]],inde
...: x=['a','b','c','d'],columns=['one','two'])

In [4]: df
Out[4]:
     one two
a 1.40 NaN
b 8.40 -3.5
c NaN NaN
d 0.65 -2.3

调用DataFrame的sum方法将会返回一个含有列小计的Series:

In [5]: df.sum()
Out[5]:
one 10.45
two -5.80
dtype: float64

传入axis=1将会按行进行求和运算:

In [6]: df.sum(axis=1)
Out[6]:
a 1.40
b 4.90
c 0.00
d -1.65
dtype: float64

NA值会自动被排除,除非整个切片(这里指的是行或列)都是NA.通过skipna选项可以禁用该功能:

In [7]: df.sum(axis=1,skipna=False)
Out[7]:
a NaN
b 4.90
c NaN
d -1.65
dtype: float64

In [8]: df.mean(axis=1,skipna=False)  #求每行的平均值,显示NA值,如果某行有NaN值,则这行平均值为NaN
Out[8]:
a NaN
b 2.450
c NaN
d -0.825
dtype: float64

下表列出了这些约简方法的常用选项。

选项                              说明

axis                          约简的轴。DataFrame的行用0,列用1

skipna                      排除缺失值,默认值为True

level                         如果轴是层次化索引的(积MultiIndex),则根据level分组约简

有些方法(如idxmin何idxmax)返回的是间接统计(比如达到最小值或最大值的索引):

In [12]: df.idxmax()
Out[12]:
one b
two d
dtype: object

In [13]: df.idxmin()
Out[13]:
one d
two b
dtype: object

另一些方法则是累计型的:

In [14]: df.cumsum()
Out[14]:
     one two
a 1.40 NaN
b 9.80 -3.5
c NaN NaN
d 10.45 -5.8

还有一种方法,它既不是约简型也不是累计型。describe就是一个例子,它用于一次性产生多个汇总统计:

In [16]: df.describe()
Out[16]:
               one         two
count 3.000000 2.000000
mean 3.483333 -2.900000
std 4.274440 0.848528
min 0.650000 -3.500000
25% 1.025000 -3.200000
50% 1.400000 -2.900000
75% 4.900000 -2.600000
max 8.400000 -2.300000

对于非数值型数据,describe会产生另一种汇总统计

In [17]: obj=Series(['a','a','b','c']*3)

In [18]: obj
Out[18]:
0 a
1 a
2 b
3 c
4 a
5 a
6 b
7 c
8 a
9 a
10 b
11 c
dtype: object

In [19]: obj.describe()
Out[19]:
count 12
unique 3
top a
freq 6
dtype: object

下表列出了所有与描述统计相关的方法。

方法                             说明

count                          非NA值的数量

describe                      针对Series或各DataFrame列计算汇总统计

min、max                   计算最小值和最大值

argmin、argmax         计算能够获取到最小值和最大值的索引位置(整数)

idxmin、idxmax           计算能够获取到最小值和最大值的索引值

quantile                       计算样本的分位数(0到1)        

sum                            值的总和

mean                        值的平均值

median                     值的算术中位数(50%分位数)

mad                          根据平均值计算平均绝对离差

var                           样本值的标准差

skew                        样本值的偏度(三阶矩)

kurt                         样本值的峰值(四阶矩)

cumsum                 样本值的累计和

cummin、cummax  样本值的累计最大值和累计最小值

cumprod                 样本值的累计积

diff                          计算一阶差分(对时间序列很有用)

pct_change            计算百分数变化

 

二.相关系数与协方差

有些汇总统计(如相关系数和协方差)是通过参数对计算出来的。我们来看几个DataFrame:

 

In [30]: df=DataFrame(np.arange(20).reshape(10,2))

In [31]: df
Out[31]:
   0 1
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9
5 10 11
6 12 13
7 14 15
8 16 17
9 18 19

 

#计算列的百分比变化,如果要计算行,设置axis=1

In [32]: df.pct_change()
Out[32]:
      0     1
0 NaN NaN
1 inf 2.000000
2 1.000000 0.666667
3 0.500000 0.400000
4 0.333333 0.285714
5 0.250000 0.222222
6 0.200000 0.181818
7 0.166667 0.153846
8 0.142857 0.133333
9 0.125000 0.117647

 

In [34]: df.pct_change(axis=1)
Out[34]:
        0 1
0 NaN inf
1 NaN 0.500000
2 NaN 0.250000
3 NaN 0.166667
4 NaN 0.125000
5 NaN 0.100000
6 NaN 0.083333
7 NaN 0.071429
8 NaN 0.062500
9 NaN 0.055556

#默认输出5行,可以设置n参数来设置输出的行数

In [33]: df.head()
Out[33]:
   0 1
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9

In [33]: df.head()
Out[33]:
   0 1
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9

In [36]: df.tail()
Out[36]:
     0 1
5 10 11
6 12 13
7 14 15
8 16 17
9 18 19

计算DataFrame列与列的相关系数和协方差

In [38]: df=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=[
...: 'one','two','three'])

In [39]: df
Out[39]:
   one two three
a  0     1     2
b  3     4     5
c  6     7     8

#计算第一列和第二列的相关系数

In [40]: df.one.corr(df.two)
Out[40]: 1.0

#返回一个相关系数矩阵

In [41]: df.corr()
Out[41]:
      one two three
one 1.0 1.0 1.0
two 1.0 1.0 1.0
three 1.0 1.0 1.0

#计算第一列和第二列的协方差

In [42]: df.one.cov(df.two)
Out[42]: 9.0

#返回一个协方差矩阵

In [43]: df.cov()
Out[43]:
       one two three
one 9.0 9.0 9.0
two 9.0 9.0 9.0
three 9.0 9.0 9.0

计算DataFrame与列或者Series的相关系数

In [38]: df=DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=[
...: 'one','two','three'])

In [39]: df
Out[39]:
   one two three
a   0    1     2
b   3    4     5
c   6     7    8

#计算df与第三列的相关系数

In [44]: df.corrwith(df.three)
Out[44]:
one 1.0
two 1.0
three 1.0
dtype: float64

#计算df与Series的相关系数,在定义Series时,索引一定要和df索引一样

In [45]: obj=Series([8,24,23],index=['a','b','c'])

In [46]: obj
Out[46]:
a 8
b 24
c 23
dtype: int64

In [47]: df.corrwith(obj)
Out[47]:
one 0.836784
two 0.836784
three 0.836784
dtype: float64

 

注意:在使用DataFrame或Series在计算相关系数或者协方差的时候,都会计算索引重叠的、非NA的、按照索引对齐原则,对于无法对齐的索引会使用NA值进行填充。在使用DataFrame与指定的行或列或Series计算协方差和相关系数的时候,默认都是与DataFrame的列进行计算,如果想要计算行,设置axis参数为1即可。

三.唯一值、值计数以及成员资格

还有一类方法可以从一维Series的值中抽取信息。以下面这个Series为例:

In [50]: obj=Series(['c','a','d','a','a','c','c','b','b'])

In [51]: obj
Out[51]:
0 c
1 a
2 d
3 a
4 a
5 c
6 c
7 b
8 b
dtype: object

 

第一个函数是unique,它可以得到Series中的唯一值数组:

In [52]: uniques=obj.unique()

In [53]: uniques
Out[53]: array(['c', 'a', 'd', 'b'], dtype=object)

返回的唯一值是未排序的,如果需要的话,可以对结果再次进行排序(uniques.sort())。value_counts用于计算一个Series各值出现的频率:

In [54]: uniques.sort()

In [58]: uniques
Out[58]: array(['a', 'b', 'c', 'd'], dtype=object)

In [60]: obj.value_counts()
Out[60]:
a 3
c 3
b 2
d 1
dtype: int64

为了便于查看,结果Series是按值频率降序排列的。value_counts还是一个顶级pandas方法,可用于任何数组或序列:

In [61]: pd.value_counts(obj.values,sort=False)
Out[61]:
d 1
c 3
b 2
a 3
dtype: int64

最后是isin,它用于判断矢量化集合的成员资格,可用于选取Series中或DataFrame列中数据的子集:

In [63]: mask=obj.isin(['b','c'])

In [64]: mask
Out[64]:
0 True
1 False
2 False
3 False
4 False
5 True
6 True
7 True
8 True
dtype: bool

In [65]: obj[mask]
Out[65]:
0 c
5 c
6 c
7 b
8 b
dtype: object

下表为唯一值,值计数,成员资格方法

方法                               说明

isin                          计算一个表示"Series各值是否包含于传入的值序列中"的布尔型数组

unique                    计算Series中的唯一值数组,按发现的顺序返回

value_counts         返回一个Series,其索引为唯一值,其值为频率,按计数值降序排列

 

四.处理缺失数据

缺失数据(missing data)在大部分数据分析应用中都很常见,pandas的设计目标之一就是让缺失数据的处理任务尽量轻松。例如,pandas对象上的所有描述统计都排除了缺失数据,正如我们在本章稍早的地方所看到的那样。

pandas使用浮点值NaN(Not a Number)表示浮点和非浮点数组中的缺失数据。它只是一个便于被检测出来的标记而已:

In [66]: s=Series(['Calvin','Kobe',np.nan,'Michale'])

In [67]: s
Out[67]:
0 Calvin
1 Kobe
2 NaN
3 Michale
dtype: object

In [68]: s.isnull()
Out[68]:
0 False
1 False
2 True
3 False
dtype: bool

Python内置的None值也会被当做NA处理:

In [69]: s[0]=None

In [70]: s.isnull()
Out[70]:
0 True
1 False
2 True
3 False
dtype: bool

不敢说pandas的NA表现形式是最优的,但它确实很简单也很可靠。由于Numpy的数据类型体系中缺乏真正的NA数据类型或位模式,所以它是能想到的最佳解决方案(一套简单的API以及足够全面的性能特征)。随着Numpy的不断发展,这个问题今后可能会发生变化。

下表为NA处理方法

方法                        说明

dropna     根据各标签的值中是否存在缺失数据对轴标签进行过滤,可通过阈值调节对缺失值的容忍度

fillna          用指定值或插值方法(如ffill或bfill)填充缺失数据

isnull         返回一个含有布尔值的对象,这些布尔值表示哪些值是缺失值NA,该对象的类型与源类型一样

notnull         isnull的否定式

1.滤除缺失数据

过滤掉缺失数据的办法有很多种。纯手工操作永远都是一个办法,但dropna可能会更实用一些。对于一个Series,dropna返回一个仅含非空数据和索引值的Series:

In [71]: from numpy import nan as NA

In [72]: data=Series([1,NA,5.5,NA,24])

In [73]: data.dropna()
Out[73]:
0 1.0
2 5.5
4 24.0
dtype: float64

当然,也可以通过布尔型索引达到这个目的:

In [74]: data[data.notnull()]
Out[74]:
0 1.0
2 5.5
4 24.0
dtype: float64

而对于DataFrame对象,事情就有点复杂了,你可能希望丢弃全NA或含有NA的行或列。dropna默认丢弃任何含有缺失值的行:

In [75]: data=DataFrame([[1,3,8.5],[1.4,NA,NA],[NA,NA,NA],[NA,8.8,3]])

In [77]: cleaned=data.dropna()

In [78]: data
Out[78]:
      0  1    2
0 1.0 3.0 8.5
1 1.4 NaN NaN
2 NaN NaN NaN
3 NaN 8.8 3.0

In [79]: cleaned
Out[79]:
    0    1     2
0 1.0 3.0 8.5

传入how='all'将只丢弃全为NA的那些行:

In [80]: cleaned=data.dropna(how='all')

In [81]: cleaned
Out[81]:
      0  1     2
0 1.0 3.0 8.5
1 1.4 NaN NaN
3 NaN 8.8 3.0

要用这种方式丢弃列,只需传入axis=1即可:

In [82]: data[4]=NA

In [83]: data
Out[83]:
     0   1     2     4
0 1.0 3.0 8.5 NaN
1 1.4 NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN 8.8 3.0 NaN

In [84]: data.dropna(axis=1,how='all')
Out[84]:
      0  1    2
0 1.0 3.0 8.5
1 1.4 NaN NaN
2 NaN NaN NaN
3 NaN 8.8 3.0

另一个滤除DataFrame行的问题涉及时间序列数据。假设你只想留下一部分观测数据,可以用thresh参数实现此目的:

In [85]: df=DataFrame(np.random.randn(7,3))

In [86]: df.iloc[:4,1]=NA;df.iloc[:2,2]=NA

In [87]: df
Out[87]:
           0         1      2
0 -0.361517 NaN NaN
1 -0.527158 NaN NaN
2 0.126102 NaN -2.513174
3 -0.585159 NaN -2.297443
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802

In [88]: df.dropna(thresh=3)
Out[88]:
          0             1               2
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802

 

2.填充缺失数据

我们可能不想滤除缺失数据(有可能会丢弃跟它有关的其他数据),而是希望通过其他方式填补那些“空洞”。对于大多数情况而言,fillna方法是最主要的函数。通过一个常数调用fillna就会将缺失值替换为那个常数值:

In [89]: df.fillna(0)
Out[89]:
           0             1             2
0 -0.361517 0.000000 0.000000
1 -0.527158 0.000000 0.000000
2 0.126102 0.000000 -2.513174
3 -0.585159 0.000000 -2.297443
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802

 

若是通过一个字典调用fillna,就可以实现对不同的列填充不同的值:

In [91]: df.fillna({1:0.5,2:-1})      #第二列NaN值填充为0,第二列的NaN值填充为-1
Out[91]:
          0              1               2
0 -0.361517 0.500000 -1.000000
1 -0.527158 0.500000 -1.000000
2 0.126102 0.500000 -2.513174
3 -0.585159 0.500000 -2.297443
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802

fillna默认会返回新对象,但也可以对现有对象进行就地修改:

#总是返回被填充对象的引用

In [92]: _=df.fillna(0,inplace=True)

In [93]: df
Out[93]:
         0               1            2
0 -0.361517 0.000000 0.000000
1 -0.527158 0.000000 0.000000
2 0.126102 0.000000 -2.513174
3 -0.585159 0.000000 -2.297443
4 1.030365 -0.192859 0.251283
5 -1.505839 -0.057001 0.193328
6 -1.102120 1.768084 0.280802

对reindex有效的那些插值方法也可用与fillna:

In [94]: df=DataFrame(np.random.randn(6,3))

In [95]: df.iloc[2:,1]=NA;df.iloc[4:,2]=NA

In [96]: df
Out[96]:
           0            1               2
0 -0.098323 -2.351729 1.333503
1 0.006153 0.344866 0.729309
2 1.830895 NaN -1.002160
3 -0.573513 NaN 0.436669
4 -1.499363 NaN NaN
5 -1.371960 NaN NaN

 

In [97]: df.fillna(method='ffill')
Out[97]:
0 1 2
0 -0.098323 -2.351729 1.333503
1 0.006153 0.344866 0.729309
2 1.830895 0.344866 -1.002160
3 -0.573513 0.344866 0.436669
4 -1.499363 0.344866 0.436669
5 -1.371960 0.344866 0.436669

In [98]: df.fillna(method='ffill',limit=2)
Out[98]:
         0               1              2
0 -0.098323 -2.351729 1.333503
1 0.006153 0.344866 0.729309
2 1.830895 0.344866 -1.002160
3 -0.573513 0.344866 0.436669
4 -1.499363 NaN 0.436669
5 -1.371960 NaN 0.436669

 

只要稍微动动脑子,我们就可以利用fillna实现许多别的功能。比如说,你可以传入Series的平均值或中位数:

In [99]: data=Series([1,NA,5.6,NA,8])

In [100]: data.fillna(data.mean())
Out[100]:
0 1.000000
1 4.866667
2 5.600000
3 4.866667
4 8.000000
dtype: float64

下表是fillna函数的参数

参数                            说明

value                  用于填充缺失值的标量值或字典对象

method              插值方式。如果函数调用时未指定其他参数的话,默认为"ffill"

axis                   待填充的轴,默认axis=0

inplace              修改调用者对象而不产生副本

limit                  (对于前向和后向)填充可以连续填充的最大数量


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM