我有一个使用pandas和列标签的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
从0.25版开始,你也可以指定errors='raise'
,在指定了无效的列名到重命名时引发错误。参见v0.25 rename()
docs。
使用df.set_axis()
axis=1
和inplace=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=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
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)
在0.21版本中,对列的重命名进行了一些重大更新。
rename
方法增加了axis
参数,可以设置为columns
或1
。
这次更新使得该方法与pandas API的其他部分一致。
它仍然有 "index "和 "columns "参数,但你不再被迫使用它们。构造样本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
rename
与axis='列'
或axis=1
。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()
我'会着重讲两件事。
我不想解决如何替换'$'
或将每个列头的第一个字符剥离的问题。
OP已经完成了这一步。
相反,我想专注于用一个新的对象替换现有的columns
对象,给定一个替换列名的列表。
df.columns = new
其中new
是新的列名列表,就是这么简单。
这种方法的缺点是需要编辑现有的数据框架'的columns
属性,而且不是内联完成。
我将向大家展示几种通过pipelining来执行的方法,而不需要编辑现有的数据框架。设置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
][1]
前面已经说过,如果你有一个字典,将旧的列名映射到新的列名,你可以使用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
][2],使用keys
参数。
首先,请注意当我们尝试使用解决方案1时,会发生什么。
df.rename(columns=dict(zip(df, new)))
y765 y765 z432
0 1 3 5
1 2 4 6
我们没有将新
列表映射为列名。
我们最终重复了y765
。
相反,我们可以使用pd.concat
函数的keys
参数,同时迭代df
的列。
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
这是和 "transpose "和 "set_index "的一个噱头。
[pd.DataFrame.set_index
][3]允许我们在线设置一个索引,但是没有对应的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 "的每个元素。
在这个解决方案中,我们传递了一个lambda,它接受x
,但忽略它。
它也接受一个y
,但并不期望它。
取而代之的是,我们给出了一个迭代器作为默认值,然后我就可以用它来一次一次地循环,而不用考虑x
的值是多少。
df.rename(columns=lambda x, y=iter(new): next(y))
x098 y765 z432
0 1 3 5
1 2 4 6
正如sopython聊天室的人向我指出的那样,如果我在x
和y
之间添加一个*
,我就可以保护我的y
变量。
虽然,在这种情况下,我不相信它需要保护。
但它仍然值得一提。
df.rename(columns=lambda x, *, y=iter(new): next(y))
x098 y765 z432
0 1 3 5
1 2 4 6
[1]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rename.html [2]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.concat.html [3]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.set_index.html
我想解释一下幕后的情况。
数据框是一组Series。
Series又是numpy.array
的扩展。
numpy.array
s有一个属性.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'
。
pd.DataFrame(df.one)
将返回。
three
0 1
1 2
2 3
因为pandas重用了已经定义好的 "系列 "的.name
。
Pandas有办法做多层次的列名。 虽然涉及的魔法并不多,但我也想在回答中涵盖这个问题,因为我没有看到有人在这里发现这个问题。
|one |
|one |two |
0 | 4 | 1 |
1 | 5 | 2 |
2 | 6 | 3 |
通过将列设置为列表,像这样,就可以轻松实现。
df.columns = [['one', 'one'], ['one', 'two']]
df = pd.DataFrame({'$a': [1], '$b': [1], '$c': [1], '$d': [1], '$e': [1]})
如果你的新列列表与现有列的顺序相同,那么分配就很简单。
new_cols = ['a', 'b', 'c', 'd', 'e']
df.columns = new_cols
>>> df
a b c d e
0 1 1 1 1 1
如果你有一个将旧列名键入新列名的字典,你可以做如下操作。
d = {'$a': 'a', '$b': 'b', '$c': 'c', '$d': 'd', '$e': 'e'}
df.columns = df.columns.map(lambda col: d[col]) # Or `.map(d.get)` as pointed out by @PiRSquared.
>>> df
a b c d e
0 1 1 1 1 1
如果你没有列表或字典映射,你可以通过列表理解来剥离前面的$
符号。
df.columns = [col[1:] if col[0] == '$' else col for col in df]
如果你已经有了数据框架,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
。
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
最好的方法吗?
一个更好的评估所有在问题的答案中提出的主要技术的方法是下面使用cProfile来测量内存&。 执行时间。 @kadee,@kaitlyn,&。 @eumiro有执行时间最快的函数--虽然这些函数的速度非常快,我们'比较所有答案的0.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)')
df.rename(index=str,columns={'A':'a','B':'b'})
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rename.html
我知道这个问题和答案已经被人嚼烂了。 但是,我参考了它的灵感,我有一个问题。 我能够使用不同答案中的零碎部分来解决它,因此提供我的回应,以备有人需要。
我的方法是通用的,你可以通过逗号分隔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
请注意,这些方法不适用于 MultiIndex。 对于 MultiIndex,你需要做一些类似下面的事情。
>>> df = pd.DataFrame({('$a','$x'):[1,2], ('$b','$y'): [3,4], ('e','f'):[5,6]})
>>> df
$a $b e
$x $y f
0 1 3 5
1 2 4 6
>>> rename = {('$a','$x'):('a','x'), ('$b','$y'):('b','y')}
>>> df.columns = pandas.MultiIndex.from_tuples([
rename.get(item, item) for item in df.columns.tolist()])
>>> df
a b e
x y f
0 1 3 5
1 2 4 6
让我们说这是你的数据框架。
[![在此输入图像描述][1]][1] 。
您可以使用两种方法重新命名列。
dataframe.columns=[#list]
。df.columns=['a','b','c','d','e']
[![在此输入图片描述][2]][2] 。
这个方法的局限性在于,如果要改变一列,必须传递完整的列列表。 另外,这个方法不适用于索引标签。 例如,如果你传递了这个方法
df.columns = ['a','b','c','d']
这将抛出一个错误。 长度不匹配。 预期的轴有5个元素,新值有4个元素。
df = df.rename(columns={'$a':'a'})
[![在此输入图片描述][3]][3] 。
[1]: https://i.stack.imgur.com/vazEj.png [2]: https://i.stack.imgur.com/uFQzo.png [3]: https://i.stack.imgur.com/sqPu9.png
同样,你也可以改变任何行或列。