描述和汇总统计

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

  1. In [48]: df = pd.DataFrame([[1.4, np.nan], [7.1, -4.6],
  2. ...: [np.nan, np.nan], [0.75, -1.3]],
  3. ...: index=['a', 'b', 'c', 'd'],
  4. ...: columns=['one', 'two'])
  5. In [49]: df
  6. Out[49]:
  7. one two
  8. a 1.40 NaN
  9. b 7.10 -4.6
  10. c NaN NaN
  11. d 0.75 -1.3

调用DataFramesum 方法将会返回一个含有列的和的Series

  1. In [50]: df.sum()
  2. Out[50]:
  3. one 9.25
  4. two -5.90
  5. dtype: float64

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

  1. In [51]: df.sum(axis=1)
  2. Out[51]:
  3. a 1.40
  4. b 2.50
  5. c 0.00
  6. d -0.55
  7. dtype: float64

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

  1. In [52]: df.mean(axis='columns', skipna=False)
  2. Out[52]:
  3. a NaN
  4. b 1.250
  5. c NaN
  6. d -0.275
  7. dtype: float64

下表列出了这些约简方法的常用选项
image.png
有些方法(如idxmaxidxmin )返回的是间接统计(比如达到最大值或最小值的索引)

  1. In [53]: df.idxmax()
  2. Out[53]:
  3. one b
  4. two d
  5. dtype: object

另一些方法则是累计型的

  1. In [54]: df.cumsum()
  2. Out[54]:
  3. one two
  4. a 1.40 NaN
  5. b 8.50 -4.6
  6. c NaN NaN
  7. d 9.25 -5.9

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

  1. one two
  2. count 3.000000 2.000000
  3. mean 3.083333 -2.950000
  4. std 3.493685 2.333452
  5. min 0.750000 -4.600000
  6. 25% 1.075000 -3.775000
  7. 50% 1.400000 -2.950000
  8. 75% 4.250000 -2.125000
  9. max 7.100000 -1.300000

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

  1. In [56]: obj = pd.Series(['a', 'a', 'b', 'c'] * 4)
  2. In [57]: obj.describe()
  3. Out[57]:
  4. count 16
  5. unique 3
  6. top a
  7. freq 8
  8. dtype: object

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

相关系数与协方差

有些汇总统计(如相关系数和协方差)是通过参数对计算出来的。我们来看几个DataFrame, 它们的数据来自Yahoo!Finance的股票价格和成交量, 使用的是pandas-datareader

  1. conda install pandas-datareader

使用pandas_datareader模块下载了一些股票数据

  1. import pandas_datareader.data as web
  2. all_data = {ticker: web.get_data_yahoo(ticker)
  3. for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG']}
  4. price = pd.DataFrame({ticker: data['Adj Close']
  5. for ticker, data in all_data.items()})
  6. volume = pd.DataFrame({ticker: data['Volume']
  7. for ticker, data in all_data.items()})

注意: 此时Yahoo! Finance已经不存在了, 因为2017年Yahoo!被Verizon收购了。 参阅pandas-datareader文档, 可以学习最新的功能

现在计算价格的百分数变化, 时间序列的操作会在第11章介绍

  1. >>> returns = price.pct_change()
  2. >>> returns.tail()
  3. AAPL GOOG IBM MSFT
  4. Date
  5. 2016-10-17 -0.000680 0.001837 0.002072 -0.003483
  6. 2016-10-18 -0.000681 0.019616 -0.026168 0.007690
  7. 2016-10-19 -0.002979 0.007846 0.003583 -0.002255
  8. 2016-10-20 -0.000512 -0.005652 0.001719 -0.004867
  9. 2016-10-21 -0.003930 0.003011 -0.012474 0.042096

Seriescorr 方法用于计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数。与此类似,cov 用于计算协方差

  1. >>> returns['MSFT'].corr(returns['IBM'])
  2. 0.49976361144151144
  3. >>> returns['MSFT'].cov(returns['IBM'])
  4. 8.8706554797035462e-05

因为MSFT 是一个合理的Python属性, 我们还可以用更简洁的语法选择列

  1. >>> returns.MSFT.corr(returns.IBM)
  2. 0.49976361144151144

另一方面,DataFramecorrcov 方法将以DataFrame的形式分别返回完整的相关系数或协方差矩阵

  1. >>> returns.corr()
  2. AAPL GOOG IBM MSFT
  3. AAPL 1.000000 0.407919 0.386817 0.389695
  4. GOOG 0.407919 1.000000 0.405099 0.465919
  5. IBM 0.386817 0.405099 1.000000 0.499764
  6. MSFT 0.389695 0.465919 0.499764 1.000000
  7. >>> returns.cov()
  8. AAPL GOOG IBM MSFT
  9. AAPL 0.000277 0.000107 0.000078 0.000095
  10. GOOG 0.000107 0.000251 0.000078 0.000108
  11. IBM 0.000078 0.000078 0.000146 0.000089
  12. MSFT 0.000095 0.000108 0.000089 0.000215

利用DataFramecorrwith 方法, 你可以计算其列或行跟另一个SeriesDataFrame之间的相关系数。传入一个Series将会返回一个相关系数值Series(针对各列进行计算)

  1. >>> returns.corrwith(return.IBM)
  2. AAPL 0.386817
  3. GOOG 0.405099
  4. IBM 1.000000
  5. MSFT 0.499764
  6. dtype: float64

传入axis='columns 即可按行进行计算。无论如何,在计算相关系数之前,所有的数据项都会按标签对齐

唯一值、值基数以及成员资格

还有一类方法可以从一维Series的值中抽取信息。看下面的例子

  1. In [3]: obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
  2. In [4]: uniques = obj.unique()
  3. In [5]: uniques
  4. Out[5]: array(['c', 'a', 'd', 'b'], dtype=object)

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

  1. In [6]: obj.value_counts()
  2. Out[6]:
  3. c 3
  4. a 3
  5. b 2
  6. d 1
  7. dtype: int64

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

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

isin 用于判断矢量化集合的成员资格,可用于过滤Series中或DataFrame列中数据的子集

  1. In [8]: obj
  2. Out[8]:
  3. 0 c
  4. 1 a
  5. 2 d
  6. 3 a
  7. 4 a
  8. 5 b
  9. 6 b
  10. 7 c
  11. 8 c
  12. dtype: object
  13. In [9]: mask = obj.isin(['b', 'c'])
  14. In [10]: mask
  15. Out[10]:
  16. 0 True
  17. 1 False
  18. 2 False
  19. 3 False
  20. 4 False
  21. 5 True
  22. 6 True
  23. 7 True
  24. 8 True
  25. dtype: bool
  26. In [11]: obj[mask]
  27. Out[11]:
  28. 0 c
  29. 5 b
  30. 6 b
  31. 7 c
  32. 8 c
  33. dtype: object

isin 类似的是Index.get_indexer 方法,它可以给你一个索引数组,从可能包含重复值的数组到另一个不同值的数组

  1. In [12]: to_match = pd.Series(['c', 'a', 'b', 'b', 'c', 'a'])
  2. In [13]: unique_vals = pd.Series(['c', 'b', 'a'])
  3. In [14]: pd.Index(unique_vals).get_indexer_for(to_match)
  4. Out[14]: array([0, 2, 1, 1, 0, 2], dtype=int64)

image.png
有时,你可能希望得到DataFrame中多个相关列的一张柱状图。例如

  1. In [16]: data = pd.DataFrame({'Qu1': [1,3,4,3,4],
  2. ...: 'Qu2': [2,3,1,2,3],
  3. ...: 'Qu3': [1,5,2,4,4]})
  4. In [17]: data
  5. Out[17]:
  6. Qu1 Qu2 Qu3
  7. 0 1 2 1
  8. 1 3 3 5
  9. 2 4 1 2
  10. 3 3 2 4
  11. 4 4 3 4

pandas.value_counts 传给该DataFrameapply 函数, 就会出现

  1. In [18]: result = data.apply(pd.value_counts).fillna(0)
  2. In [19]: result
  3. Out[19]:
  4. Qu1 Qu2 Qu3
  5. 1 1.0 1.0 1.0
  6. 2 0.0 2.0 1.0
  7. 3 2.0 2.0 0.0
  8. 4 2.0 0.0 2.0
  9. 5 0.0 0.0 1.0