【读书笔记】《利用Python进行数据分析》第2版_第八章 数据规整:连接、联合与重塑

8.1 分层索引

分层索引允许在一个轴向上拥有多个(两个或两个以上)索引层级

Series分层索引

  • 创建

    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]])
    """输出
    a  1   -0.204708
       2    0.478943
       3   -0.519439
    b  1   -0.555730
       3    1.965781
    c  1    1.393406
       2    0.092908
    d  2    0.281746
       3    0.769023
    dtype: float64
    """
    
  • 各种索引方式

    # 以MultiIndex作为索引的Series的美化视图
    data.index
    """
    MultiIndex([('a', 1),
                ('a', 2),
                ('a', 3),
                ('b', 1),
                ('b', 3),
                ('c', 1),
                ('c', 2),
                ('d', 2),
                ('d', 3)],
               )
    """
    # 分层索引
    data['b']
    data['b':'c']
    data.loc[['b', 'd']]
    """
    b  1   -0.555730
       3    1.965781
    d  2    0.281746
       3    0.769023
    dtype: float64
    """
    # 在“内部”层级中进行选择
    data.loc[:, 2]
    """
    a    0.478943
    c    0.092908
    d    0.281746
    dtype: float64
    """
    
    

DataFrame分层索引

  • unstack重新排列

    data.unstack() # 将数据在DataFrame中重新排列
    """
    1	2	3
    a	-0.204708	0.478943	-0.519439
    b	-0.555730	NaN	1.965781
    c	1.393406	0.092908	NaN
    d	NaN	0.281746	0.769023
    """
    data.unstack().stack()  # unstack反操作
    # 输出结果为原来模样
    
    image-20220403103053939
  • 在DataFrame中每一层都可以拥有分层索引

    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']])
    
    image-20220403100304726

分层索引名称

  • 分层的层级可以有名称(字符串或Python对象)

    frame.index.names = ['key1', 'key2']
    frame.columns.names = ['state', 'color']
    
    frame['Ohio']
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a3G3tbSH-1648984382595)(C:/Users/TSY/Desktop/无标题.png?lastModify=1648949532)]

  • MultiIndex对象可以使用其自身的构造函数创建并复用

    pd.MultiIndex.from_arrays([['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']],
                           names=['state', 'color'])
    """
    MultiIndex([(    'Ohio', 'Green'),
                (    'Ohio',   'Red'),
                ('Colorado', 'Green')],
               names=['state', 'color'])
    """
    

重排序和层级排序

重新排列轴上的层级顺序

按照特定层级的值对数据进行排序

  • swaplevel接收两个层级序号层级名称,返回进行层级变更的新对象(但是数据是不变的)

    frame.swaplevel('key1', 'key2')
    
    image-20220403102450286
  • sort_index只能在单一层级上进行排序,在层级变换时,可以按照层级进行字典排序

    frame.sort_index(level=1)
    frame.swaplevel(0, 1).sort_index(level=0)
    
    1

    按照字典最外层开始排序数据选择效果更好,调用sort_index(level=0)或sort_index可以实现

按层级进行汇总统计

  • 在描述性和汇总性统计中使用level选项实现在特定轴上进行聚合

    # level要被弃用,使用group代替
    frame.sum(level='key2')
    # frame.groupby(level='key2').sum()
    frame.sum(level='color', axis=1)
    # frame.groupby(level='color',axis=1).sum()
    
    22

使用DataFrame的列进行索引

  • DataFrame数据

    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]})
    
    image-20220403105650872
  • DataFrame的set_index函数和reset_index函数

    frame2 = frame.set_index(['c', 'd'])
    frame2
    
    # set_index函数会生成一个新的DataFrame,新的DataFrame使用一个或多个列作为索引
    # 默认这些列会从DataFrame中移除
    frame.set_index(['c', 'd'], drop=False)
    
    # reset_index是set_index的反操作,分层索引的索引层级会被移动到列中
    frame2.reset_index()
    
    re_set

8.2 联合与合并数据集

pandas数据联合方式

  • pandas.merge根据一个或多个键将行进行连接,数据库的连接操作
  • pandas.concat使对象在轴向上进行黏合或“堆叠”
  • combine_first实例方法允许将重叠的数据拼接在一起,以使用一个对象中的值填充另一个对象中的缺失值

数据库风格的DataFrame连接

  • pandas.merge函数:将各种join操作运用在数据上

    df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
                        'data1': range(7)})
    df2 = pd.DataFrame({'key': ['a', 'b', 'd'],
                        'data2': range(3)})
    print(df1)
    """
      key  data1
    0   b      0
    1   b      1
    2   a      2
    3   c      3
    4   a      4
    5   a      5
    6   b      6
    """
    print(df2)
    """
      key  data2
    0   a      0
    1   b      1
    2   d      2
    """
    
  • 使用merge进行多对一连接

    • 简单示例

      # merge会自动将重叠列名作为连接的键
      pd.merge(df1, df2)
      
      pd.merge(df1, df2, on='key') # 显示指定键
      """
      key	data1	data2
      0	b	0	1
      1	b	1	1
      2	b	6	1
      3	a	2	0
      4	a	4	0
      5	a	5	0
      """
      
    • merge默认内连接,只出现表的交集;有可选项’left’、‘right’和’outer’(外连接是键的并集)

      df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
                          'data1': range(7)})
      df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'],
                          'data2': range(3)})
      print(df3)
      print(df4)
      # 指定列名
      pd.merge(df3, df4, left_on='lkey', right_on='rkey') # 内连接
      
      pd.merge(df1, df2, how='outer') # 外连接
      
      内外
    • how参数的不同连接类型

      epub_22739904_103
  • 使用merge进行多对多连接

    • 多对多连接是行的笛卡尔积

    • 使用多个键进行合并时,传入一个列名的列表

      pd.merge(left, right, on=['key1', 'key2'], how='outer')
      

当你在进行列-列连接时,传递的DataFrame索引对象会被丢弃

  • 重叠列名

    • 手动重命名轴标签

    • merge的suffixes后缀选项:在左右两边有重叠列名时指定需要添加的字符串

      pd.merge(left, right, on='key1', suffixes=('_left', '_right'))
      
      image-20220403114948604
  • merge函数参数

    img

根据索引合并

  • 合并的键是它的索引,可以传递left_index=True或right_index=True(或者都传)来表示索引需要用来作为合并的键。

    left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'],
                          'value': range(6)})
    right1 = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])
    left1
    right1
    # 默认:连键相交
    pd.merge(left1, right1, left_on='key',right_index=True)
    """
    	key	value	group_val
    0	a	0	3.5
    2	a	2	3.5
    3	a	3	3.5
    1	b	1	7.0
    4	b	4	7.0
    """
    
    # 使用外键进行合并
    pd.merge(left1, right1, left_on='key', right_index=True, how='outer')
    """
    key	value	group_val
    0	a	0	3.5
    2	a	2	3.5
    3	a	3	3.5
    1	b	1	7.0
    4	b	4	7.0
    5	c	5	NaN
    """
    
  • 多层索引数据:隐式的多键合并

    # 必须以列表的方式指明合并所需多个列(请注意使用how='outer’处理重复的索引值)
    # 在多层索引数据的情况下,在索引上连接是一个隐式的多键合并
    pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True)
    pd.merge(lefth, righth, left_on=['key1', 'key2'],
            right_index=True, how='outer')
    # 使用两边的索引进行合并
    pd.merge(left2, right2, how='outer', left_index=True, right_index=True)
    
    333 444
  • DataFrame的join方法:用于按照索引合并,也可用于合并多个索引相同或相似但没有重叠列的DataFrame对象

    left2.join(right2, how='outer')
    
    • join方法进行左连接,完全保留左边DataFrame的行索引;支持在连接上传递索引

      left1.koin(right1,one='key')
      
    • 索引-索引,向join方法传入DataFrame列表

      # concat方法更为通用
      left2.join([right2, another], how='outer')
      

沿轴向连接

  • NumPy的concatenate函数在NumPy数组上实现拼接、绑定或堆叠

    arr = np.arange(12).reshape((3, 4))
    arr
    np.concatenate([arr, arr], axis=1)
    """
    array([[ 0,  1,  2,  3,  0,  1,  2,  3],
           [ 4,  5,  6,  7,  4,  5,  6,  7],
           [ 8,  9, 10, 11,  8,  9, 10, 11]])
    """
    
  • pandas的concat函数

    • 假设存在三个索引不存在重叠的Series

      s1 = pd.Series([0, 1], index=['a', 'b'])
      s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])
      s3 = pd.Series([5, 6], index=['f', 'g'])
      # 使用concat连接 ,默认沿着axis=0的轴向生效的
      pd.concat([s1, s2, s3])
      # 传递axis=1,返回的结果则是一个DataFrame(axis=1时是列)
      pd.concat([s1, s2, s3], axis=1)
      
      heb
    • 有重叠轴

      s4 = pd.concat([s1, s3])
      pd.concat([s1, s4], axis=1)
      pd.concat([s1, s4], axis=1, join='inner') # 标签f和g消失
      s4
      """s4
      a    0
      b    1
      f    5
      g    6
      dtype: int64
      """
      
    • 在连接轴上建立多层索引,使用参数keys来实现:区分连接前的各部分

      result = pd.concat([s1, s1, s3], keys=['one', 'two', 'three'])
      result
      """
      one    a    0
             b    1
      two    a    0
             b    1
      three  f    5
             g    6
      dtype: int64
      """
      
      • 沿着轴向axis=1连接Series的时候,keys则成为DataFrame的列头

        pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three'])
        
        image-20220403140431340
      • Series扩展到DataFrame对象

        df1 = pd.DataFrame(np.arange(6).reshape(3, 2), index=['a', 'b', 'c'],
                           columns=['one', 'two'])
        df2 = pd.DataFrame(5 + np.arange(4).reshape(2, 2), index=['a', 'c'],
                           columns=['three', 'four'])
        
        pd.concat([df1, df2], axis=1, keys=['level1', 'level2'])
        
        image-20220403140557533
      • 如果传递字典,字典的键会用于keys选项

        pd.concat({'level1': df1, 'level2': df2}, axis=1)
        
      • 使用names参数生成轴层级

        pd.concat([df1, df2], axis=1, keys=['level1', 'level2'],names=['upper', 'lower'])
        
        image-20220403140811873
      • 行索引中不包含任何相关数据的DataFrame,传入ignore_index = True

  • concat函数的参数(join_axes好像已经弃用)

    img

联合重叠数据

展示几种数据有重叠部分的情况

  • NumPy的where函数,面向数组的if-else等价操作

    a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan],
                  index=['f', 'e', 'd', 'c', 'b', 'a'])
    b = pd.Series(np.arange(len(a), dtype=np.float64),
                  index=['f', 'e', 'd', 'c', 'b', 'a'])
    b[-1] = np.nan
    print(a)
    print(b)
    np.where(pd.isnull(a), b, a)
    
    image-20220403142053075
  • Series的combine_first方法,类似于pandas常见的数据对齐逻辑的轴向操作;针对DataFrame逐列做相同的操作。

    b.combine_first(a)
    

8.3 重塑和透视

重排列表格型数据的操作被称为重塑或透视

使用多层索引进行重塑

两个基础操作

  • stack(堆叠):该操作会“旋转”或将列中的数据透视到行
  • unstack(拆堆):该操作会将行中的数据透视到列

例子说明

  • 效果演示

    data = pd.DataFrame(np.arange(6).reshape((2, 3)),
                        index=pd.Index(['Ohio', 'Colorado'], name='state'),
                        columns=pd.Index(['one', 'two', 'three'],
                        name='number'))
    """
    number	one	two	three
    state			
    Ohio	0	1	2
    Colorado	3	4	5
    """
    # 用stack方法会将列透视到行,产生一个新的Series
    result = data.stack()
    result
    """
    state     number
    Ohio      one       0
              two       1
              three     2
    Colorado  one       3
              two       4
              three     5
    dtype: int32
    """
    # 使用unstack方法将数据重排列后放入一个DataFrame中
    result.unstack() # 还原
    
  • 默认最内层是已拆堆的,可以传入层级序号或名称来拆分一个不同的层级

    result.unstack(0) # 传入序号来拆分不同的层级
    result.unstack('state') # 传入名称来拆分不同的层级
    
    image-20220403174621301
  • 拆堆可能会引入缺失值,堆叠会过滤出缺失值,两个操作可逆

  • 在DataFrame中拆堆时,被拆堆的层级会变为结果中最低的层级

  • 在调用stack方法时,我们可以指明需要堆叠的轴向名称

    df.unstack('state').stack('side')
    
    image-20220403175303626

将“长”透视为“宽”

在数据库和CSV中存储多时间序列的方式就是所谓的长格式或堆叠格式

  • 使用PeriodIndex将数据处理后形成Idata

    image-20220403183953595

    多时间序列的长格式,或具有两个或更多个键的数据(键date和item)

  • 使用DataFrame的pivot方法将数据处理为按date列时间戳进行索引且每个不同的item独立为一列

    # 前两个值是分别用作行和列索引的列
    # 然后是可选的数值列以填充DataFrame
    pivoted = ldata.pivot('date', 'item', 'value')
    pivoted
    
    image-20220403184419500
  • 同时重塑两个数值列

    ldata['value2'] = np.random.randn(len(ldata))
    ldata[:10]
    
    image-20220403184717460

    遗漏最后一个参数,你会得到一个含有多层列的DataFrame

    pivoted = ldata.pivot('date', 'item')
    pivoted[:5]
    
    image-20220403184906941
  • pivot方法等价于使用set_index创建分层索引,然后调用unstack

    unstacked = ldata.set_index(['date','item']).unstack('item')
    unstacked[:7]
    

将“宽”透视为“长”

DataFrame的pivot方法的反操作:pandas.melt,将多列合并成一列,产生一个新的DataFrame

  • 数据image-20220403190157927

  • 'key’列可以作为分组指标,其他列均为数据值

    melted = pd.melt(df, ['key'])
    
    image-20220403190300797
  • 使用pivot方法可以重回原来布局

    reshaped = melted.pivot('key', 'variable', 'value')
    # pivot的结果根据作为行标签的列生成了索引
    # 使用reset_index来将数据回移一列
    reshaped.reset_index()
    
    1111
  • 可以指定列的子集作为值列,也可以无须任何分组指标

    # 指定列的子集作为值列
    pd.melt(df, id_vars=['key'], value_vars=['A', 'B'])
    # 无须任何分组指标直接使用
    pd.melt(df, value_vars=['A', 'B', 'C'])
    pd.melt(df, value_vars=['key', 'A', 'B'])
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值