[Python] 重命名熊猫中的列


Answers

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

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

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

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

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

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




如果你不想要行名df.columns = ['a', 'b',index=False]




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




尝试这个。 这个对我有用

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



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

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

要么

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



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

是解决这个问题的一种功能性方式




我知道这个问题和答案已被咀嚼死亡。 但是我提到它是为了解决我遇到的一个问题。 我能够使用不同答案中的零件来解决问题,因此可以在任何需要的情况下提供我的答案。

我的方法是通用的,其中您可以添加额外的分隔符,用逗号分隔delimiters=可变和不受时间delimiters=

工作代码:

import pandas as pd
import re


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

delimiters = '$'
matchPattern = '|'.join(map(re.escape, delimiters))
df.columns = [re.split(matchPattern, i)[1] for i in df.columns ]

输出:

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

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



熊猫0.21+答案

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

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

熊猫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与list和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.columns = ['Name1', 'Name2', 'Name3'...]

它会按照您放置的顺序分配列名称




我认为这种方法很有用:

df.rename(columns={"old_column_name1":"new_column_name1", "old_column_name2":"new_column_name2"})

该方法允许您单独更改列名称。




一条线或管线解决方案

我将专注于两件事情:

  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_index的噱头戏法。 pd.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中使用循环遍历new每个元素的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



如果您有数据框,则df.columns会将所有内容转储到您可以操作的列表中,然后将其重新分配到您的数据框中作为列的名称...

columns = df.columns
columns = [row.replace("$","") for row in columns]
df.rename(columns=dict(zip(columns, things)), inplace=True)
df.head() #to validate the output

最好的办法? IDK。 一种方式 - 是的。

评估问题答案中提出的所有主要技术的更好方法是使用cProfile来测量内存和执行时间。 @kadee,@kaitlyn和@eumiro具有最快执行时间的功能 - 虽然这些功能非常快,但我们正在比较所有答案的.000和0.001秒舍入。 道德:我上面的回答可能不是'最好'的方式。

import pandas as pd
import cProfile, pstats, re

old_names = ['$a', '$b', '$c', '$d', '$e']
new_names = ['a', 'b', 'c', 'd', 'e']
col_dict = {'$a': 'a', '$b': 'b','$c':'c','$d':'d','$e':'e'}

df = pd.DataFrame({'$a':[1,2], '$b': [10,20],'$c':['bleep','blorp'],'$d':[1,2],'$e':['texa$','']})

df.head()

def eumiro(df,nn):
    df.columns = nn
    #This direct renaming approach is duplicated in methodology in several other answers: 
    return df

def lexual1(df):
    return df.rename(columns=col_dict)

def lexual2(df,col_dict):
    return df.rename(columns=col_dict, inplace=True)

def Panda_Master_Hayden(df):
    return df.rename(columns=lambda x: x[1:], inplace=True)

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

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

def migloo(df,on,nn):
    return df.rename(columns=dict(zip(on, nn)), inplace=True)

def kadee(df):
    return df.columns.str.replace('$','')

def awo(df):
    columns = df.columns
    columns = [row.replace("$","") for row in columns]
    return df.rename(columns=dict(zip(columns, '')), inplace=True)

def kaitlyn(df):
    df.columns = [col.strip('$') for col in df.columns]
    return df

print 'eumiro'
cProfile.run('eumiro(df,new_names)')
print 'lexual1'
cProfile.run('lexual1(df)')
print 'lexual2'
cProfile.run('lexual2(df,col_dict)')
print 'andy hayden'
cProfile.run('Panda_Master_Hayden(df)')
print 'paulo1'
cProfile.run('paulo1(df)')
print 'paulo2'
cProfile.run('paulo2(df)')
print 'migloo'
cProfile.run('migloo(df,old_names,new_names)')
print 'kadee'
cProfile.run('kadee(df)')
print 'awo'
cProfile.run('awo(df)')
print 'kaitlyn'
cProfile.run('kaitlyn(df)')