Pandas:df.set_value()方法擦除/重置MultiIndex的列名

时间:2013-03-25 17:33:02

标签: python pandas

我正在编写一个使用pandas(版本0.10.1)的应用程序将底层数据模型存储为(3级)MultiIndex的DataFrame。该模型是线谱,索引的顶层是原子转换。

简单的数据框可能如下所示:

                               Pos     Sigma       Ampl  Line center Identifier
H-alpha-6697.6 30-30 Comp2  -3.600  0.774000  33.058000       6699.5          b
                     Comp3   3.538  2.153000  28.054000       6699.5          c
                     Contin    NaN       NaN   0.000000          NaN        NaN
                     Comp4   1.384  0.921000  37.504000       6699.5          d
                     Comp1  -2.124  1.977000  69.166000       6699.5          a
               31-31 Comp2  -3.292  0.884603  49.813423       6699.5          b
                     Comp3   3.600  2.299000  19.999000       6699.5          c
                     Contin    NaN       NaN   0.000000          NaN        NaN
                     Comp4   1.692  1.009000  22.222000       6699.5          d
                     Comp1  -1.262  2.534000  68.002000       6699.5          a

在某些时候,我需要能够创建一个不同的过渡,例如H-beta,使用H-alpha作为模板。理想情况下我会通过类似df.ix['H-beta-wavelength'] = df.ix['H-alpha-6697.6']的方式来做这件事,但这是不可能做到的。相反,我尝试了以下示例:Prepend a level to a pandas MultiIndex

但是,上面的示例需要设置.names多索引级别才能对它们进行重新排序。并且在初始化数据帧时设置了names属性,但是在构建它时,我非常依赖set_values()方法,并且这样做会破坏names属性 - 或者更确切地说将它们设置为[None, None, None]

示例:

In [68]: df
Out[68]: 
                                  Pos  Sigma     Ampl  Line center Identifier
Transition     Rows  Component                                               
Center: 6699.5 26-26 Comp2     -3.846  0.657  15.2740       6699.5          b
                     Comp3      2.924  1.449  31.3930       6699.5          c
                     Contin       NaN    NaN   0.0000          NaN        NaN
                     Comp4      8.030  1.009   7.0831       6699.5          d
                     Comp1     -1.816  2.153  50.2750       6699.5          a

In [69]: df.set_value(('Center: 5044.3', '26-26', 'Comp1'), 'Sigma', 2.457)
Out[69]: 
                               Pos  Sigma     Ampl  Line center Identifier
Center: 6699.5 26-26 Comp2  -3.846  0.657  15.2740       6699.5          b
                     Comp3   2.924  1.449  31.3930       6699.5          c
                     Contin    NaN    NaN   0.0000          NaN        NaN
                     Comp4   8.030  1.009   7.0831       6699.5          d
                     Comp1  -1.816  2.153  50.2750       6699.5          a
Center: 5044.3 26-26 Comp1     NaN  2.457      NaN          NaN        NaN

当然,这使得使用名称重新排序多索引的级别变得非常困难。有没有办法避免这种情况,每次运行set_values()后,没有蛮力设置名称?

编辑:更简单,可重复的例子。

这是一个iPython会话,用一个稍微简单的例子重新创建index.names问题。它还表明它可能是一个超出index.names的错误,因为它似乎将index.lexsort_depth从3更改为0.提示中缺少的数字只是数据帧的不必要的视图。 我认为必须选择已经存在的二级和/或三级指数,就像我在下面所做的那样,以便重现它。

In [4]: idx = pd.MultiIndex.from_arrays(
            [['Hans']*4 + ['Grethe']*4, ['1', '1', '2', '2']*2, ['a', 'b']*4], 
            names=['Name', 'Number', 'Letter'])

In [5]: df = pd.DataFrame(
            random.random((8, 3)), 
            columns=['one', 'two','three'], 
            index=idx)


In [6]: df
Out[6]: 
                           one       two     three
Name   Number Letter                              
Hans   1      a       0.803566  0.434574  0.805976
              b       0.655322  0.208469  0.989559
       2      a       0.893952  0.380358  0.173764
              b       0.822446  0.673894  0.676573
Grethe 1      a       0.202641  0.387263  0.405296
              b       0.646733  0.086953  0.882114
       2      a       0.358458  0.147107  0.769586
              b       0.183782  0.477863  0.601098

# To rule out another possible source of problems:
In [9]: df.unstack().drop(('Grethe', '1')).stack()
Out[9]: 
                           one       two     three
Name   Number Letter                              
Grethe 2      a       0.358458  0.147107  0.769586
              b       0.183782  0.477863  0.601098
Hans   1      a       0.803566  0.434574  0.805976
              b       0.655322  0.208469  0.989559
       2      a       0.893952  0.380358  0.173764
              b       0.822446  0.673894  0.676573

In [10]: df.set_value(('Frans', '2', 'b'), 'one', 23.)
Out[10]: 
                  one       two     three
Hans   1 a   0.803566  0.434574  0.805976
         b   0.655322  0.208469  0.989559
       2 a   0.893952  0.380358  0.173764
         b   0.822446  0.673894  0.676573
Grethe 1 a   0.202641  0.387263  0.405296
         b   0.646733  0.086953  0.882114
       2 a   0.358458  0.147107  0.769586
         b   0.183782  0.477863  0.601098
Frans  2 b  23.000000       NaN       NaN

In [11]: df = df.sortlevel(level='Name')

In [13]: df.index.lexsort_depth
Out[13]: 3

In [14]: df.set_value(('Frans', '2', 'b'), 'one', 23.).index.lexsort_depth
Out[14]: 0

2 个答案:

答案 0 :(得分:1)

您的索引需要排序!请参阅此处的文档:http://pandas.pydata.org/pandas-docs/dev/indexing.html#the-need-for-sortedness,这些食谱可能会有所帮助http://pandas.pydata.org/pandas-docs/dev/cookbook.html 这也是0.10.1

Heres一个有序的框架

In [26]: index = pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
              names=['first', 'second'])

In [27]: df = pd.DataFrame(np.random.rand(len(index)), index=index,columns=['A'])

In [7]: df.index.lexsort_depth
Out[7]: 2

In [28]: df.set_value(('a',1),'A',1)
Out[28]: 
                     A
first second          
a     1       1.000000
      2       0.136456
b     1       0.712612
      2       0.818473

如果我按第二级排序(因此未排序)

In [29]: df2 = df.sortlevel(level='second')

# this is not sorted! (well it is, just not lexsorted)
In [10]: df2.index.lexsort_depth
Out[10]: 0

In [30]: df2.set_value(('b','1'),'A',2)
Out[30]: 
            A
a 1  1.000000
b 1  0.712612
a 2  0.136456
b 2  0.818473
  1  2.000000

答案 1 :(得分:0)

根据Andy Hayden的说法,这是熊猫中的names虫。 希望很快就能解决问题。

在此之前,我认为最好的方法是执行以下操作:

tmp = df.ix['ExistingTransition'].copy()
tmp['Transition'] = 'NewTransition'
tmp = tmp.set_index('Transition', append=True)
tmp.index = tmp.index.reorder_levels([2, 0, 1])
# ...Do whatever else needs to be done to this before applying as template...
df = df.append(tmp)

...那或者确保在每次names运行后重新创建set_values()属性,然后按照问题中链接的示例进行操作。