8.1中的操作名
- join:连接
- combine:合并
- reshape:整形
8.2中的操作名
- merge:归并
- concatenate:串联
8.3中的操作名
- pivot:旋转
- stack:堆叠
【Chapter 8.1】分层索引
Hierarchical Indexing是pandas中一个重要的特性,能让我们在一个轴(axis)上有多个index levels(索引层级)。它可以让我们在低维格式下处理高维数据。这里给出一个简单的例子,构建一个series,其index是a list of lists:
data = pd.Series(np.random.randn(9),
index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'],
[1, 2, 3, 1, 3, 1, 2, 2, 3]])
data
Out[543]:
a 1 0.428315
2 -1.045874
3 -0.991650
b 1 -1.418607
3 -0.295123
c 1 1.368846
2 -0.692923
d 2 2.690562
3 0.133222
dtype: float64
其中我们看到的是把MultiIndex作为index(索引)的,美化过后series。
data.index
Out[544]:
MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],
labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 2, 0, 1, 1, 2]])
于这种分层索引对象,partial indexing(部分索引)也是能做到的,这种方法可以让我们简洁地选中数据的一部分:
data['b']
Out[545]:
1 -1.418607
3 -0.295123
dtype: float64
data['b': 'c']
Out[546]:
b 1 -1.418607
3 -0.295123
c 1 1.368846
2 -0.692923
dtype: float64
data.loc[['b', 'd']]
Out[547]:
b 1 -1.418607
3 -0.295123
d 2 2.690562
3 0.133222
dtype: float64
selection(选中)对于一个内部层级(inner level)也是可能的:
data.loc[:, 2]
Out[548]:
a -1.045874
c -0.692923
d 2.690562
dtype: float64
分层索引的作用是改变数据的形状,以及做一些基于组的操作(group-based)比如做一个数据透视表(pivot table)。例子,我们可以用unstack来把数据进行重新排列,产生一个DataFrame:
data.unstack()
Out[550]:
1 2 3
a 0.428315 -1.045874 -0.991650
b -1.418607 NaN -0.295123
c 1.368846 -0.692923 NaN
d NaN 2.690562 0.133222
相反的操作是stack:
data.unstack().stack()
Out[551]:
a 1 0.428315
2 -1.045874
3 -0.991650
b 1 -1.418607
3 -0.295123
c 1 1.368846
2 -0.692923
d 2 2.690562
3 0.133222
dtype: float64
之后的章节会对unstack和stack做更多介绍。
对于dataframe,任何一个axis(轴)都可以有一个分层索引:
frame = pd.DataFrame(np.arange(12).reshape((4, 3)),
index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
columns=[['Ohio', 'Ohio', 'Colorado'],
['Green', 'Red', 'Green']])
frame
Out[552]:
Ohio Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
每一层级都可以有一个名字(字符串或任何python对象)。如果有的话,这些会显示在输出中:
frame.index.names = ['key1', 'key2']
frame.columns.names = ['state', 'color']
frame
Out[555]:
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
这里我们要注意区分行标签(row label)中索引的名字'state'和'color'。
如果想要选中部分列(partial column indexing)的话,可以选中一组列(groups of columns):
frame['Ohio']
Out[556]:
color Green Red
key1 key2
a 1 0 1
2 3 4
b 1 6 7
2 9 10
MultiIndex能被同名函数创建,而且可以重复被使用;在DataFrame中给列创建层级名可以通过以下方式:
pd.MultiIndex.from_arrays([['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']],
names=['state', 'color'])
1 Reordering and Sorting Levels(重排序和层级排序)
有时候我们需要在一个axis(轴)上按层级进行排序,或者在一个层级上,根据值来进行排序。swaplevel会取两个层级编号或者名字,并返回一个层级改变后的新对象(数据本身并不会被改变):
frame.swaplevel('key1', 'key2')
Out[558]:
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11
另一方面,sort_index则是在一个层级上,按数值进行排序。比如在交换层级的时候,通常也会使用sort_index,来让结果按指示的层级进行排序:
frame.sort_index(level=1)
Out[559]:
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11
frame.sort_index(level='color')
frame.sort_index(level='state')
# 这两个语句都会报错
(按照我的理解,level指的是key1和key2,key1是level=0,key2是level=1。可以看到下面的结果和上面是一样的:)
frame.sort_index(level='key2')
Out[564]:
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11
frame.swaplevel(0, 1).sort_index(level=0) # 把key1与key2交换后,按key2来排序
Out[565]:
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
b 6 7 8
2 a 3 4 5
b 9 10 11
如果index是按词典顺序那种方式来排列的话(比如从外层到内层按a,b,c这样的顺序),在这种多层级的index对象上,数据选择的效果会更好一些。这是我们调用sort_index(level=0) or sort_index()
2 Summary Statistics by Level (按层级来归纳统计数据)
在DataFrame和Series中,一些描述和归纳统计数据都是有一个level选项的,这里我们可以指定在某个axis下,按某个level(层级)来汇总。比如上面的DataFrame,我们可以按 行 或 列的层级来进行汇总:
frame
Out[566]:
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
frame.sum(level='key2')
Out[567]:
state Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16
frame.sum(level='color', axis=1)
Out[568]:
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10
3 Indexing with a DataFrame’s columns(利用DataFrame的列来索引)
把DataFrame里的一列或多列作为行索引(row index)是一件很常见的事;另外,我们可能还希望把行索引变为列。这里有一个例子:
frame = pd.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
Out[569]:
a b c d
0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
3 3 4 two 0
4 4 3 two 1
5 5 2 two 2
6 6 1 two 3
DataFrame的set_index会把列作为索引,并创建一个新的DataFrame:
frame2 = frame.set_index(['c', 'd'])
frame2
Out[570]:
a b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
3 6 1
默认删除原先的列,当然我们也可以留着:
frame.set_index(['c', 'd'], drop=False)
Out[571]:
a b c d
c d
one 0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
two 0 3 4 two 0
1 4 3 two 1
2 5 2 two 2
3 6 1 two 3
另一方面,reset_index的功能与set_index相反,它会把多层级索引变为列:
frame2.reset_index()
Out[572]:
c d a b
0 one 0 0 7
1 one 1 1 6
2 one 2 2 5
3 two 0 3 4
4 two 1 4 3
5 two 2 5 2
6 two 3 6 1