利用Python进行数据分析


[TOC]

chapter 05

索引对象

  • Index对象是不可更改的(immutable)。
    index[1]=\'d\'就会出错。但是,df.index=index_new是可以的。

  • 对于reindex可以修改(行)索引、列,或两个都修改。1
    frame.reindex(columns=states)重新索引列。

  • df.drop([list1,list2])默认是删除的指定的行,如果想要删除某一列,就需要df.drop([list1,list2],axis=1)
    自己的认识,axis是指查找数据的一个方向,axis=0是指查找数据时是竖直方向去找,axis=1是水平方向去找数据。这样,这里想要删除某一列,就需要是水平方向去找到该列名。否则,提示找不到。

索引、选取和过滤

  • Series索引,Series索引值不止是整数。

obj = Series(np.arange(4.), index=[\'a\', \'b\', \'c\', \'d\'])
obj[0]
obj[:2]    #找到:obj[0],obj[1]
obj[\'a\']
obj[[\'a\',\'c\']]
obj[\'a\':\'c\'] #找到:obj[0],obj[1],obj[2]  标签索引,闭区间!

以上索引方式都可以。

利用标签的切片运算和普通的Python切片运算是不同的,其末端是包含的(inclusive)。闭区间

  • 对DataFrame索引其实就是获取一个或多个列。

data = DataFrame(np.arange(16).reshape((4, 4)),
                 index=[\'Ohio\', \'Colorado\', \'Utah\', \'New York\'],
                 columns=[\'one\', \'two\', \'three\', \'four\'])
data[\'two\']
data[[\'three\',\'one\']]

这时候,不能像Series那样直接选取行了,如:data[\'Ohio\']

那么,选择行怎么做呢?

# 这里举例选取前三行
data[:3] 选取了0,1,2行
# 或者
data.ix[\'Ohio\':\'Utah\',:]   
# 或者
data.ix[0:3]
# 或者
data.loc[\'Ohio\':\'Utah\',:]
# 或者
data.iloc[0:3,:] 

以上,后边的冒号可以省略。

  • ix标签索引,位置索引都可以

  • loc标签索引

  • iloc位置索引

再强调一遍,标签索引是闭区间!

  • 布尔索引

data[data[\'three\']>5]
data[data<5]
data.ix[data.three>5,:3]

总结下来,ix索引最牛逼!灵活结合了标签索引和位置索引!

算数运算和数据对齐

pandas最重要的一个功能是,它可以对不同索引的对象进行算数运算。

对于DataFrame,对齐操作将会同时发生在行和列上。

没有重叠的位置会产生NA值–NaN

在算数方法中填充值。

广播功能,需要注意索引,如果某个索引值在DataFrame或者Series的索引中找不到,则参与运算就会容易形成NA值。

如果希望匹配行且在列上广播,则必须使用算术运算方法。例如:

series3 = frame[\'d\']
frame.sub(series3, axis=0)


结果:

b d e
Utah -1.0 0.0 1.0
Ohio -1.0 0.0 1.0
Texas -1.0 0.0 1.0
Oregon -1.0 0.0 1.0

函数应用和映射

元素及的Python函数也是可以的。假如想得到frame中各个浮点值的格式化字符串,使用applymap函数。

frame = DataFrame(np.random.randn(4, 3), columns=list(\'bde\'),
                  index=[\'Utah\', \'Ohio\', \'Texas\', \'Oregon\'])
format = lambda x: \'%.2f\' % x
frame.applymap(format)

之所以叫applymap,是因为Series有一个应用于元素级函数的map方法:

frame[\'e\'].map(format)

带有重复值的轴索引

虽然许多pandas函数(如reindex)都要求标签唯一,但这并不是强制的。

obj = Series(range(5), index=[\'a\', \'a\', \'b\', \'b\', \'c\'])
obj.index.is_unique   #False

索引的`is_unique属性可以告诉你它的值是否唯一。
obj[\'a\']会返回两个值。

汇总和计算描述统计

NA值会自动被排除。通过skipna选项可以禁用该功能。

意思是,df.mean(axis=1,skipna=False)会计算水平方向的均值,并且,有NA出现,均值也会是NA,而不是忽视它。

  • idxmin返回最小值的索引

  • idxman返回最大值的索引

相关系数与协方差

有些汇总统计是通过参数对计算出来的。

看几个DataFrame,他们的数据来自Yahoo!Finance的股票价格和成交量。

import pandas.io.data as web

all_data = {}
for ticker in [\'AAPL\', \'IBM\', \'MSFT\', \'GOOG\']:
    all_data[ticker] = web.get_data_yahoo(ticker)

price = DataFrame({tic: data[\'Adj Close\']
                   for tic, data in all_data.iteritems()})
volume = DataFrame({tic: data[\'Volume\']
                    for tic, data in all_data.iteritems()})


计算价格的百分数变化:

returns = price.pct_change()

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

returns.MSFT.corr(returns.IBM)
returns.MSFT.cov(returns.IBM)

利用DataFrame的corrwith方法,可以计算其列或行跟另一个Series或者DataFrame之间的相关系数。

returns.corrwith(returns.IBM)
#等价于
returns.corr()[\'IBM\']

无论如何,在计算相关系数之前,所有的数据项都会按标签对齐。

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

  • unique函数可以得到Series中唯一值数组。

  • value_counts函数用于计算Series中各值出现的频率。

  • isin用于选取矢量化集合的成员资格。

这几个函数都是Series数据的方法!

result = data.apply(pd.value_counts).fillna(0)

利用上面这个方法,可以对df数据每列出现的数值频率进行统计,同时,对有的列中没有出现的数值的频率为NA的值设置为0

apply看来这个函数还是很有用啊,它是默认从列角度(axis=0)去应用里边的函数。而applymap是元素级应用函数。

处理缺失数据

之前看一篇文章,机器学习系列(3)_逻辑回归应用之Kaggle泰坦尼克之灾2,当中遇到缺失数据之后,运用机器学习的方法,结合其他变量拟合预测出值,然后作为缺失值的填充。

而本书立足于数据分析,从处理数据角度出发,因此,不会采用那么复杂的方法。这里,是要介绍一些操作数据的函数方法,这是基础,是之后处理数据的基本功!缺失数据也是重中之重!

pandas的设计目标之一就是让缺失数据的处理任务尽量轻松。例如,pandas对象上的描述统计都排除了缺失数据!

string_data = Series([\'aardvark\', \'artichoke\', np.nan, \'avocado\'])
string_data
0     aardvark
1    artichoke
2          NaN
3      avocado
dtype: object

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

NA处理方法

滤除缺失数据

dropna方法可能比较实用一点。

from numpy import nan as NA
data = Series([1, NA, 3.5, NA, 7])
data.dropna()

对于一个Series, dropna返回一个仅含非空数据和索引值的Series。

0    1.0
2    3.5
4    7.0
dtype: float64

而对于一个DataFrame对象,事情就有点复杂了。dropna默认丢弃任何含有缺失值的行。

data = DataFrame([[1., 6.5, 3.], [1., NA, NA],
                  [NA, NA, NA], [NA, 6.5, 3.]])
cleaned = data.dropna()
data

cleaned
    0    1    2
0    1.0    6.5    3.0

传入how=\'all\'将只丢弃全为NA的行。要用这种方式丢弃列,只需要传入参数axis=1

data.dropna(how=\'all\')
0    1    2
0    1.0    6.5    3.0
1    1.0    NaN    NaN
3    NaN    6.5    3.0

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

df = DataFrame(np.random.randn(7, 3))
df.ix[:4, 1] = NA; df.ix[:2, 2] = NA
df
       0        1             2
0    -0.577087    NaN            NaN
1    0.523772    NaN            NaN
2    -0.713544    NaN            NaN
3    -1.860761    NaN            0.560145
4    -1.265934    NaN            -1.063512
5    0.332883    -2.359419    -0.199543
6    -1.541996    -0.970736    -1.307030
df.dropna(thresh=3)

保留至少3个非空值的行。


        0        1            2
5    0.332883    -2.359419    -0.199543
6    -1.541996    -0.970736    -1.307030

填充缺失数据

  • 对于大多数情况而言,fillna方法是最主要的函数。通过一个常数调用fillna就会将缺失值替换为那个常数。df.fillna(0)

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

df.fillna({1:0.5,3:-1})

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

df.fillna(0,inplace=True)
  • reindex有效地那些插值方法,也可用以fillna

df = DataFrame(np.random.randn(6, 3))
df.ix[2:, 1] = NA; df.ix[4:, 2] = NA
df
df.fillna(method=\'ffill\', limit=2)
# 有很多灵活的填充方式
data = Series([1., NA, 3.5, NA, 7])
data.fillna(data.mean())


层次化索引

层次化索引(hierarchical indexing)是pandas的一项重要功能,它使你能在一个轴上拥有多个(两个以上)索引级别。

抽象点说,它使你能以低纬度形式处理高纬度数据。

data = Series(np.random.randn(10),
              index=[[\'a\', \'a\', \'a\', \'b\', \'b\', \'b\', \'c\', \'c\', \'d\', \'d\'],
                     [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
data
a  1   -0.204708
   2    0.478943
   3   -0.519439
b  1   -0.555730
   2    1.965781
   3    1.393406
c  1    0.092908
   2    0.281746
d  2    0.769023
   3    1.246435
dtype: float64
  • 这段数据可以通过其unstack方法被重新安排到一个DataFrame中:

data.unstack()

    1            2            3
a    -0.204708    0.478943    -0.519439
b    -0.555730    1.965781    1.393406
c    0.092908    0.281746    NaN
d    NaN            0.769023    1.246435
  • unstack的逆方法是stack.

不要将索引名称(index.names)跟轴标签混为一谈!

重排分级顺序(Reordering and sorting levels)

有时,你需要重新调整某条轴上各级别的顺序,或根据指定级别上的值对数据进行排序。

  • swaplevel接受两个级别编号或名称,并返回一个互换了级别的新对象(但数据不会发生变化)

根据级别汇总统计

许多对DataFrame和Series的描述和汇总统计都有一个level选项,它用于指定在某条轴上求和的级别。

这其实是利用了pandas的groupby功能。

使用DataFrame的列(充当索引)

人们经常想要将DataFrame的一个或多个列当做行索引来用,或者可能希望将行索引变成DataFrame的列。

frame = DataFrame({\'a\': range(7), \'b\': range(7, 0, -1),
                   \'c\': [\'one\', \'one\', \'one\', \'two\', \'two\', \'two\', \'two\'],
                   \'d\': [0, 1, 2, 0, 1, 2, 3]})
frame

  • DataFrmae的set_index函数会将其一个或多个列转换为行索引,并创建一个新的DataFrame:

frame2 = frame.set_index([\'c\', \'d\'])


默认情况下,那系列会从DataFrame中移除,但也可以将其保留下来。

frame.set_index([\'c\', \'d\'], drop=False)

  • reset_index的功能跟set_index刚好相反,层次化索引的级别会被转移到列里边。

frame2.reset_index()


  1. pandas.DataFrame.reindex ↩
  2. 机器学习系列(3)_逻辑回归应用之Kaggle泰坦尼克之灾 ↩