重命名熊猫列

我有一个使用熊猫和列标签的 DataFrame,我需要对其进行编辑以替换原始列标签。

我想在原始列名称为的 DataFrame A中更改列名称:

['$a', '$b', '$c', '$d', '$e']

['a', 'b', 'c', 'd', 'e'].

我已经将编辑后的列名存储在列表中,但是我不知道如何替换列名。

答案

重命名特定列

使用df.rename()函数并引用要重命名的列。并非所有列都必须重命名:

df = df.rename(columns={'oldName1': 'newName1', 'oldName2': 'newName2'})
# Or rename the existing DataFrame (rather than creating a copy) 
df.rename(columns={'oldName1': 'newName1', 'oldName2': 'newName2'}, inplace=True)

最小代码示例

df = pd.DataFrame('x', index=range(3), columns=list('abcde'))
df

   a  b  c  d  e
0  x  x  x  x  x
1  x  x  x  x  x
2  x  x  x  x  x

下列方法均起作用并产生相同的输出:

df2 = df.rename({'a': 'X', 'b': 'Y'}, axis=1)  # new method
df2 = df.rename({'a': 'X', 'b': 'Y'}, axis='columns')
df2 = df.rename(columns={'a': 'X', 'b': 'Y'})  # old method  

df2

   X  Y  c  d  e
0  x  x  x  x  x
1  x  x  x  x  x
2  x  x  x  x  x

切记将结果分配回去,因为修改未就位。或者,指定inplace=True

df.rename({'a': 'X', 'b': 'Y'}, axis=1, inplace=True)
df

   X  Y  c  d  e
0  x  x  x  x  x
1  x  x  x  x  x
2  x  x  x  x  x

从 v0.25 开始,如果指定了无效的要重命名的列,您还可以指定errors='raise'引发错误。参见v0.25 named rename() docs


REASSIGN 列标题

df.set_axis()axis=1inplace=False (以返回副本)。

df2 = df.set_axis(['V', 'W', 'X', 'Y', 'Z'], axis=1, inplace=False)
df2

   V  W  X  Y  Z
0  x  x  x  x  x
1  x  x  x  x  x
2  x  x  x  x  x

这将返回一个副本,但是您可以通过设置 inplace inplace=Trueinplace=True修改 DataFrame(这是版本 <= 0.24 的默认行为,但将来可能会更改)。

您还可以直接分配标题:

df.columns = ['V', 'W', 'X', 'Y', 'Z']
df

   V  W  X  Y  Z
0  x  x  x  x  x
1  x  x  x  x  x
2  x  x  x  x  x

只需将其分配给.columns属性即可:

>>> df = pd.DataFrame({'$a':[1,2], '$b': [10,20]})
>>> df.columns = ['a', 'b']
>>> df
   a   b
0  1  10
1  2  20

rename方法可以使用函数 ,例如:

In [11]: df.columns
Out[11]: Index([u'$a', u'$b', u'$c', u'$d', u'$e'], dtype=object)

In [12]: df.rename(columns=lambda x: x[1:], inplace=True)

In [13]: df.columns
Out[13]: Index([u'a', u'b', u'c', u'd', u'e'], dtype=object)

http://pandas.pydata.org/pandas-docs/stable/text.html 中所述

df.columns = df.columns.str.replace('$','')

熊猫 0.21 + 答案

0.21 版中对列重命名进行了一些重大更新。

  • rename方法添加了axis参数,可以将其设置为columns1 。此更新使该方法与其他 pandas API 匹配。它仍然具有indexcolumns参数,但是您不再被迫使用它们。
  • set_axis方法inplace设置为False ,您可以重命名列表中的所有索引或列标签。

熊猫的例子 0.21+

构造样本 DataFrame:

df = pd.DataFrame({'$a':[1,2], '$b': [3,4], 
                   '$c':[5,6], '$d':[7,8], 
                   '$e':[9,10]})

   $a  $b  $c  $d  $e
0   1   3   5   7   9
1   2   4   6   8  10

axis='columns'axis=1使用rename

df.rename({'$a':'a', '$b':'b', '$c':'c', '$d':'d', '$e':'e'}, axis='columns')

要么

df.rename({'$a':'a', '$b':'b', '$c':'c', '$d':'d', '$e':'e'}, axis=1)

两者都导致以下结果:

a  b  c  d   e
0  1  3  5  7   9
1  2  4  6  8  10

仍然可以使用旧的方法签名:

df.rename(columns={'$a':'a', '$b':'b', '$c':'c', '$d':'d', '$e':'e'})

rename函数还接受将应用于每个列名称的函数。

df.rename(lambda x: x[1:], axis='columns')

要么

df.rename(lambda x: x[1:], axis=1)

set_axis与列表一起使用set_axis inplace=False

您可以向set_axis方法提供一个列表,该列表的长度等于列(或索引)的数量。当前, inplace默认为True ,但在将来的版本中inplace将默认为False

df.set_axis(['a', 'b', 'c', 'd', 'e'], axis='columns', inplace=False)

要么

df.set_axis(['a', 'b', 'c', 'd', 'e'], axis=1, inplace=False)

为什么不使用df.columns = ['a', 'b', 'c', 'd', 'e']

像这样直接分配列没有错。这是一个完美的解决方案。

使用set_axis的优点是它可以用作方法链的一部分,并返回 DataFrame 的新副本。没有它,您将不得不在重新分配列之前将链的中间步骤存储到另一个变量。

# new for pandas 0.21+
df.some_method1()
  .some_method2()
  .set_axis()
  .some_method3()

# old way
df1 = df.some_method1()
        .some_method2()
df1.columns = columns
df1.some_method3()

由于只想删除所有列名中的 $ 符号,因此可以执行以下操作:

df = df.rename(columns=lambda x: x.replace('$', ''))

要么

df.rename(columns=lambda x: x.replace('$', ''), inplace=True)
df.columns = ['a', 'b', 'c', 'd', 'e']

它将按照您提供的顺序用您提供的名称替换现有名称。

old_names = ['$a', '$b', '$c', '$d', '$e'] 
new_names = ['a', 'b', 'c', 'd', 'e']
df.rename(columns=dict(zip(old_names, new_names)), inplace=True)

这样,您可以根据需要手动编辑new_names 。当您只需要重命名几列以纠正拼写错误,重音符号,删除特殊字符等时,效果很好。

一线或管道解决方案

我将专注于两件事:

  1. OP 明确指出

    我已经将编辑后的列名存储在列表中,但是我不知道如何替换列名。

    我不想解决如何替换'$'或从每个列标题中删除第一个字符的问题。 OP 已完成此步骤。相反,我想集中精力用给定替换列名称列表的新对象替换现有的columns对象。

  2. df.columns = new ,其中new是新列名称的列表,它变得非常简单。这种方法的缺点是,它需要编辑现有数据框的columns属性,并且不能内联完成。我将展示一些通过流水执行此操作而不编辑现有数据框的方法。


设置 1
为了专注于使用现有列表重命名替换列名称的需求,我将创建一个带有初始列名称和不相关的新列名称的新示例数据框df

df = pd.DataFrame({'Jack': [1, 2], 'Mahesh': [3, 4], 'Xin': [5, 6]})
new = ['x098', 'y765', 'z432']

df

   Jack  Mahesh  Xin
0     1       3    5
1     2       4    6

解决方案 1
pd.DataFrame.rename

已经有人说过, 如果您有一个将旧列名映射到新列名的字典,则可以使用pd.DataFrame.rename

d = {'Jack': 'x098', 'Mahesh': 'y765', 'Xin': 'z432'}
df.rename(columns=d)

   x098  y765  z432
0     1     3     5
1     2     4     6

但是,您可以轻松创建该词典并将其包含在rename的调用中。以下内容利用了以下事实:迭代df ,我们迭代每个列名。

# given just a list of new column names
df.rename(columns=dict(zip(df, new)))

   x098  y765  z432
0     1     3     5
1     2     4     6

如果您原始的列名是唯一的,那么这很好。但是,如果不是这样,那么就会崩溃。


设置 2
非唯一列

df = pd.DataFrame(
    [[1, 3, 5], [2, 4, 6]],
    columns=['Mahesh', 'Mahesh', 'Xin']
)
new = ['x098', 'y765', 'z432']

df

   Mahesh  Mahesh  Xin
0       1       3    5
1       2       4    6

解决方案 2
pd.concat使用keys参数

首先,请注意当我们尝试使用解决方案 1 时会发生什么:

df.rename(columns=dict(zip(df, new)))

   y765  y765  z432
0     1     3     5
1     2     4     6

我们没有将new列表映射为列名。我们最后重复了y765 。相反,我们可以在遍历df的列时使用pd.concat函数的keys参数。

pd.concat([c for _, c in df.items()], axis=1, keys=new) 

   x098  y765  z432
0     1     3     5
1     2     4     6

解决方案 3
重建。仅当所有列都有单个dtype ,才应使用此选项。否则,您将为所有列使用dtype object ,将它们转换回需要更多的词典工作。

dtype

pd.DataFrame(df.values, df.index, new)

   x098  y765  z432
0     1     3     5
1     2     4     6

混合dtype

pd.DataFrame(df.values, df.index, new).astype(dict(zip(new, df.dtypes)))

   x098  y765  z432
0     1     3     5
1     2     4     6

解决方案 4
这是一个花哨的技巧与transposeset_indexpd.DataFrame.set_index允许我们内联设置索引,但是没有相应的set_columns 。这样我们就可以转置,然后set_index ,然后转回。但是,此处适用解决方案 3 中相同的单一dtype与混合dtype警告。

dtype

df.T.set_index(np.asarray(new)).T

   x098  y765  z432
0     1     3     5
1     2     4     6

混合dtype

df.T.set_index(np.asarray(new)).T.astype(dict(zip(new, df.dtypes)))

   x098  y765  z432
0     1     3     5
1     2     4     6

解决方案 5
pd.DataFrame.rename中使用一个lambda循环遍历new每个元素
在此解决方案中,我们传递一个带x的 lambda,然后将其忽略。它也需要y但不要期望。取而代之的是,将迭代器指定为默认值,然后我可以使用该迭代器一次遍历一个迭代器,而不必考虑x的值是什么。

df.rename(columns=lambda x, y=iter(new): next(y))

   x098  y765  z432
0     1     3     5
1     2     4     6

正如人们在sopython聊天中向我指出的那样,如果在xy之间添加* ,则可以保护y变量。但是,在这种情况下,我认为它不需要保护。仍然值得一提。

df.rename(columns=lambda x, *, y=iter(new): next(y))

   x098  y765  z432
0     1     3     5
1     2     4     6

列名称与系列名称

我想解释一下幕后发生的事情。

数据框是一组系列。

系列又是numpy.array的扩展

numpy.array具有属性.name

这是系列的名称。很少有人会尊重大熊猫的这一属性,但它会在某些地方徘徊,并可以用来破解某些大熊猫的行为。

命名列列表

这里有很多答案都谈到df.columns属性实际上是一个Series list 。这意味着它具有.name属性。

如果您决定填写列Series的名称,则会发生这种情况:

df.columns = ['column_one', 'column_two']
df.columns.names = ['name of the list of columns']
df.index.names = ['name of the index']

name of the list of columns     column_one  column_two
name of the index       
0                                    4           1
1                                    5           2
2                                    6           3

请注意,索引的名称总是低一列。

that 绕的神器

.name属性有时会持续存在。如果设置df.columns = ['one', 'two']df.one.name将为'one'

如果将df.one.name = 'three'设置df.one.name = 'three'df.columns仍然会给您['one', 'two'] ,而df.one.name会给您'three'

pd.DataFrame(df.one)将返回

three
0       1
1       2
2       3

因为 pandas 重用了已经定义的Series.name

多级列名称

熊猫有做多层列名的方法。没有太多魔术,但是我也想在答案中涵盖这一点,因为我看不到有人在这里进行这项工作。

|one            |
    |one      |two  |
0   |  4      |  1  |
1   |  5      |  2  |
2   |  6      |  3  |

通过将列设置为列表很容易实现,如下所示:

df.columns = [['one', 'one'], ['one', 'two']]