Pandas:更改具有多级列的数据框中特定列的名称

21

我希望找到更改多级数据框中特定列名称的方法。

使用以下数据:

data = {
    ('A', '1', 'I'): [1, 2, 3, 4, 5], 
    ('B', '2', 'II'): [1, 2, 3, 4, 5], 
    ('C', '3', 'I'): [1, 2, 3, 4, 5], 
    ('D', '4', 'II'): [1, 2, 3, 4, 5], 
    ('E', '5', 'III'): [1, 2, 3, 4, 5], 
}

dataDF = pd.DataFrame(data)

这段代码无法运行:

dataDF.rename(columns = {('A', '1', 'I'):('Z', '100', 'Z')}, inplace=True)

结果:

    A   B   C   D   E
    1   2   3   4   5
    I   II  I   II  III
0   1   1   1   1   1
1   2   2   2   2   2
2   3   3   3   3   3
3   4   4   4   4   4
4   5   5   5   5   5

也不是这样:

dataDF.columns.values[0] = ('Z', '100', 'Z')

结果:

    A   B   C   D   E
    1   2   3   4   5
    I   II  I   II  III
0   1   1   1   1   1
1   2   2   2   2   2
2   3   3   3   3   3
3   4   4   4   4   4
4   5   5   5   5   5

但是以上代码的组合起来可以正常工作!!!

dataDF.columns.values[0] = ('Z', '100', 'Z')
dataDF.rename(columns = {('A', '1', 'I'):('Z', '100', 'Z')}, inplace=True)
dataDF

结果:

    Z   B   C   D   E
    100 2   3   4   5
    Z   II  I   II  III
0   1   1   1   1   1
1   2   2   2   2   2
2   3   3   3   3   3
3   4   4   4   4   4
4   5   5   5   5   5

这是Pandas的一个bug吗?

3个回答

29

这是我的理论

pandas 不希望 pd.Index 是可变的。如果我们尝试自己更改索引的第一个元素,就会发现这一点。

dataDF.columns[0] = ('Z', '100', 'Z')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-32-2c0b76762235> in <module>()
----> 1 dataDF.columns[0] = ('Z', '100', 'Z')
//anaconda/envs/3.5/lib/python3.5/site-packages/pandas/indexes/base.py in __setitem__(self, key, value)
   1372 
   1373     def __setitem__(self, key, value):
-> 1374         raise TypeError("Index does not support mutable operations")
   1375 
   1376     def __getitem__(self, key):
TypeError: Index does not support mutable operations

但是pandas无法控制您对values属性的操作。
dataDF.columns.values[0] = ('Z', '100', 'Z')

我们可以看到,dataDF.columns 看起来没变化,但是 dataDF.columns.values 明显反映了变化。不幸的是,df.columns.values 并没有显示在数据帧的显示中。
另一方面,这确实看起来应该有效。事实上,它不起作用让我感到很奇怪。
dataDF.rename(columns={('A', '1', 'I'): ('Z', '100', 'Z')}, inplace=True)

我认为之所以只有在更改值后才能起作用的原因是,rename强制重新构造列并查看值。由于我们改变了值,现在它可以工作了。这非常笨拙,我不建议依赖这种过程来构建流程。

我的建议

  • 确定要更改的列名的位置
  • 将列名分配给值数组
  • 从头开始明确构建新的列

from_col = ('A', '1', 'I')
to_col = ('Z', '100', 'Z')
colloc = dataDF.columns.get_loc(from_col)
cvals = dataDF.columns.values
cvals[colloc] = to_col

dataDF.columns = pd.MultiIndex.from_tuples(cvals.tolist())

dataDF

enter code here


4
dataDF.columns.values[0] = ('Z', '100', 'Z') 对我来说是可行的。在此之后打印 dataDF.columns 反映出更改是正确的。这里有什么我忽略的东西吗?Pandas 在更新版本中解决了这个问题吗? - Jon

1
您可以像这样简单地更改它:DF.columns.levels=[[u'Z', u'B', u'C', u'D', u'E'],[u'5', u'2', u'3', u'4', u'5'],[u'IIIIII', u'II', u'III']]

我仍然不确定它是否是你所说的错误。 - Dark Matter

1

当我自己尝试在具有多个级别的数据框中重命名列名时,我遇到了这个问题。我尝试了@Dark Matter提供的解决方案,因为它似乎是一个非常简单的解决方案:

dataDF.columns.levels = [[u'Z', u'B', u'C', u'D', u'E'], [u'100', u'2', u'3', u'4', u'5'], [u'Z', u'II', u'III']]

但是出现了一个错误信息:
C:\anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: setting `levels` directly is deprecated. Use set_levels instead
  """Entry point for launching an IPython kernel.

看起来它之前能用,但现在不能用了。所以我使用了:

dataDF.columns.set_levels([['Z', 'B', 'C', 'D', 'E'],
                           ['100', '2', '3', '4', '5'],
                           ['Z', 'II', 'III']],
                          [0, 1, 2], inplace=True)

结果: dataDF
Z   B   C   D   E
100 2   3   4   5
Z   II  Z   II  III
0   1   1   1   1   1
1   2   2   2   2   2
2   3   3   3   3   3
3   4   4   4   4   4
4   5   5   5   5   5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接