当前位置: 首页>>技术教程>>正文


重命名 Pandas 中DataFrame的多个列

我在Pandas中使用带列名的DataFrame,我需要编辑以替换或者说重命名原来的列名(标签)。

示例如下:我想更改DataFrame A中的列名,其中原始列名是:

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

想改为

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

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

Pandas重命dataframe名列名

 

最佳解决方案

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

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

 

次佳解决方案

使用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)

 

第三种解决方案

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)

 

第四种方案

既然你只想删除所有列名中的$符号,你可以这样做:

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

要么

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

 

第五种方案

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

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

 

第六种方案

df.columns = ['a', 'b', 'c', 'd', 'e']

上面的代码会按照您提供的顺序,用您提供的名称替换现有名称。

也可以像这样通过索引来修改它们:

df.columns.values[2] = 'c'    #renames the 2nd column to 'c'

 

第七种方案

Pandas 0.21+答案

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

  • rename方法添加了可设置为columns1axis参数。此更新使此方法与 Pandas API的其余部分相匹配。它仍然有indexcolumns参数,但不再强制使用它们。
  • inplace设置为Falseset_axis方法可以使用列表重命名所有索引或列标签。

Pandas 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与列表和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()

 

第八种方案

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。当您只需重新命名几列以纠正拼写错误,重音符号,删除特殊字符等时,它的效果非常好。

 

第九种方案

列名与系列的名称

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

数据框是一组系列。

系列又是numpy.array的延伸

numpy.array有一个属性.name

这是该系列的名称。 Pandas 很少尊重这个属性,但它在某些地方徘徊,可以用来攻击一些 Pandas 的行为。

命名列的列表

这里有很多答案都谈到了df.columns属性是list,实际上它是Series。这意味着它有一个.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

请注意,索引的名称始终低一列。

徘徊的文物

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

如果你设置了df.one.name = 'three',那么df.columns仍然会给你['one', 'two'],而df.one.name会给你'three'

BUT

pd.DataFrame(df.one)将返回

    three
0       1
1       2
2       3

因为 Pandas 重复使用已定义的Series.name

多级别的列名称

Pandas 有办法做多层列名。没有太多的魔术参与,但我想在我的回答中加以说明,因为我没有看到任何人在此采访。

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

通过将列设置为列表可以轻松实现,如下所示:

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

 

第十种方案

一条线或管线解决方案

我将专注于两件事情:

  1. OP明确声明我已将编辑的列名存储在列表中,但我不知道如何替换列名。我不想解决如何替换'$'或从每个列标题剥离第一个字符的问题。 OP已经完成了这一步。相反,我想专注于用给定的替换列名称列表替换现有的columns对象。
  2. df.columns = new其中new是新列名称的列表非常简单。这种方法的缺点是它需要编辑现有数据框的columns属性,而不是内联完成的。我将通过流水线显示几种方式来执行此操作,而无需编辑现有数据框。

安装程序1为了专注于重新命名使用pre-existing列表替换列名称的需要,我将创建一个新的示例数据框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个non-unique列

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使用keys参数的pd.concat

首先,注意当我们尝试使用解决方案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_index的噱头。 pd.DataFrame.set_index允许我们设置内联索引,但没有相应的set_columns。所以我们可以转置,然后set_index,并转置回来。但是,在这里适用同一个dtype与来自解决方案3的混合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使用循环遍历new的每个元素的pd.DataFrame.rename中的lambda在此解决方案中,我们传递一个需要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

参考资料

 

本文由《纯净天空》出品。文章地址: https://vimsky.com/article/3838.html,未经允许,请勿转载。