【Chapter 8.1】层次化索引

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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,635评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,543评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,083评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,640评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,640评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,262评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,833评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,736评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,280评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,369评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,503评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,870评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,340评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,460评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,909评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,512评论 2 359

推荐阅读更多精彩内容