描述和汇总统计
pandas对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从Series中提取单个值(如 sum
或mean
)或从DataFrame的行或列中提取一个Series。跟对应的NumPy数组方法相比,它们都是基于没有缺失数据的假设而构建的。 看一个简单的DataFrame
In [48]: df = pd.DataFrame([[1.4, np.nan], [7.1, -4.6],
...: [np.nan, np.nan], [0.75, -1.3]],
...: index=['a', 'b', 'c', 'd'],
...: columns=['one', 'two'])
In [49]: df
Out[49]:
one two
a 1.40 NaN
b 7.10 -4.6
c NaN NaN
d 0.75 -1.3
调用DataFrame的sum
方法将会返回一个含有列的和的Series
In [50]: df.sum()
Out[50]:
one 9.25
two -5.90
dtype: float64
传入axis='columns'
或axis=1
将会按行进行求和运算
In [51]: df.sum(axis=1)
Out[51]:
a 1.40
b 2.50
c 0.00
d -0.55
dtype: float64
NA值会自动被排除,除非整个切片(这里指的是行或列)都是NA。通过skipna
选项可以禁用该功能
In [52]: df.mean(axis='columns', skipna=False)
Out[52]:
a NaN
b 1.250
c NaN
d -0.275
dtype: float64
下表列出了这些约简方法的常用选项
有些方法(如idxmax
和idxmin
)返回的是间接统计(比如达到最大值或最小值的索引)
In [53]: df.idxmax()
Out[53]:
one b
two d
dtype: object
另一些方法则是累计型的
In [54]: df.cumsum()
Out[54]:
one two
a 1.40 NaN
b 8.50 -4.6
c NaN NaN
d 9.25 -5.9
还有一种方法,它既不是约简型也不是累计型。describe
就是一个例子,它用于一次性产生多个汇总统计
one two
count 3.000000 2.000000
mean 3.083333 -2.950000
std 3.493685 2.333452
min 0.750000 -4.600000
25% 1.075000 -3.775000
50% 1.400000 -2.950000
75% 4.250000 -2.125000
max 7.100000 -1.300000
对于非数值型数据,describe
会产生另外一种汇总统计
In [56]: obj = pd.Series(['a', 'a', 'b', 'c'] * 4)
In [57]: obj.describe()
Out[57]:
count 16
unique 3
top a
freq 8
dtype: object
相关系数与协方差
有些汇总统计(如相关系数和协方差)是通过参数对计算出来的。我们来看几个DataFrame, 它们的数据来自Yahoo!Finance的股票价格和成交量, 使用的是pandas-datareader包
conda install pandas-datareader
使用pandas_datareader模块下载了一些股票数据
import pandas_datareader.data as web
all_data = {ticker: web.get_data_yahoo(ticker)
for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG']}
price = pd.DataFrame({ticker: data['Adj Close']
for ticker, data in all_data.items()})
volume = pd.DataFrame({ticker: data['Volume']
for ticker, data in all_data.items()})
注意: 此时Yahoo! Finance已经不存在了, 因为2017年Yahoo!被Verizon收购了。 参阅pandas-datareader文档, 可以学习最新的功能
现在计算价格的百分数变化, 时间序列的操作会在第11章介绍
>>> returns = price.pct_change()
>>> returns.tail()
AAPL GOOG IBM MSFT
Date
2016-10-17 -0.000680 0.001837 0.002072 -0.003483
2016-10-18 -0.000681 0.019616 -0.026168 0.007690
2016-10-19 -0.002979 0.007846 0.003583 -0.002255
2016-10-20 -0.000512 -0.005652 0.001719 -0.004867
2016-10-21 -0.003930 0.003011 -0.012474 0.042096
Series的 corr
方法用于计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数。与此类似,cov
用于计算协方差
>>> returns['MSFT'].corr(returns['IBM'])
0.49976361144151144
>>> returns['MSFT'].cov(returns['IBM'])
8.8706554797035462e-05
因为MSFT
是一个合理的Python属性, 我们还可以用更简洁的语法选择列
>>> returns.MSFT.corr(returns.IBM)
0.49976361144151144
另一方面,DataFrame的corr
和cov
方法将以DataFrame的形式分别返回完整的相关系数或协方差矩阵
>>> returns.corr()
AAPL GOOG IBM MSFT
AAPL 1.000000 0.407919 0.386817 0.389695
GOOG 0.407919 1.000000 0.405099 0.465919
IBM 0.386817 0.405099 1.000000 0.499764
MSFT 0.389695 0.465919 0.499764 1.000000
>>> returns.cov()
AAPL GOOG IBM MSFT
AAPL 0.000277 0.000107 0.000078 0.000095
GOOG 0.000107 0.000251 0.000078 0.000108
IBM 0.000078 0.000078 0.000146 0.000089
MSFT 0.000095 0.000108 0.000089 0.000215
利用DataFrame的corrwith
方法, 你可以计算其列或行跟另一个Series或DataFrame之间的相关系数。传入一个Series将会返回一个相关系数值Series(针对各列进行计算)
>>> returns.corrwith(return.IBM)
AAPL 0.386817
GOOG 0.405099
IBM 1.000000
MSFT 0.499764
dtype: float64
传入axis='columns
即可按行进行计算。无论如何,在计算相关系数之前,所有的数据项都会按标签对齐
唯一值、值基数以及成员资格
还有一类方法可以从一维Series的值中抽取信息。看下面的例子
In [3]: obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
In [4]: uniques = obj.unique()
In [5]: uniques
Out[5]: array(['c', 'a', 'd', 'b'], dtype=object)
返回的唯一值是未排序的,如果需要的话,可以对结果再次进行排序uniques.sort()
。相似的,value_counts
用于计算一个Series中各值出现的频率
In [6]: obj.value_counts()
Out[6]:
c 3
a 3
b 2
d 1
dtype: int64
为了便于查看,结果Series是按值频率降序排列的。value_counts
还是一个顶级pandas方法,可用于任何数组或序列
In [7]: pd.value_counts(obj.values, sort=False)
Out[7]:
d 1
b 2
a 3
c 3
dtype: int64
isin
用于判断矢量化集合的成员资格,可用于过滤Series中或DataFrame列中数据的子集
In [8]: obj
Out[8]:
0 c
1 a
2 d
3 a
4 a
5 b
6 b
7 c
8 c
dtype: object
In [9]: mask = obj.isin(['b', 'c'])
In [10]: mask
Out[10]:
0 True
1 False
2 False
3 False
4 False
5 True
6 True
7 True
8 True
dtype: bool
In [11]: obj[mask]
Out[11]:
0 c
5 b
6 b
7 c
8 c
dtype: object
与isin
类似的是Index.get_indexer
方法,它可以给你一个索引数组,从可能包含重复值的数组到另一个不同值的数组
In [12]: to_match = pd.Series(['c', 'a', 'b', 'b', 'c', 'a'])
In [13]: unique_vals = pd.Series(['c', 'b', 'a'])
In [14]: pd.Index(unique_vals).get_indexer_for(to_match)
Out[14]: array([0, 2, 1, 1, 0, 2], dtype=int64)
有时,你可能希望得到DataFrame中多个相关列的一张柱状图。例如
In [16]: data = pd.DataFrame({'Qu1': [1,3,4,3,4],
...: 'Qu2': [2,3,1,2,3],
...: 'Qu3': [1,5,2,4,4]})
In [17]: data
Out[17]:
Qu1 Qu2 Qu3
0 1 2 1
1 3 3 5
2 4 1 2
3 3 2 4
4 4 3 4
将pandas.value_counts
传给该DataFrame的apply
函数, 就会出现
In [18]: result = data.apply(pd.value_counts).fillna(0)
In [19]: result
Out[19]:
Qu1 Qu2 Qu3
1 1.0 1.0 1.0
2 0.0 2.0 1.0
3 2.0 2.0 0.0
4 2.0 0.0 2.0
5 0.0 0.0 1.0