我有一个 df X,其列具有重复的名称:
In [77]: X_R
Out[77]:
dollars dollars
0 0.7085 0.5000
我想重命名它,这样我就可以:
In [77]: X_R
Out[77]:
Retail Cost
0 0.7085 0.5000
使用 Pandas 重命名功能确实有效:
X_R.rename(index=str, columns={"dollars": "Retail", "dollars": "Cost"})
只给我两列名为“成本”的列。
在这种情况下如何重命名列?
这是一个动态解决方案:
In [59]: df
Out[59]:
a x x x z
0 6 2 7 7 8
1 6 6 3 1 1
2 6 6 7 5 6
3 8 3 6 1 8
4 5 7 5 3 0
In [60]: d
Out[60]: {'x': ['x1', 'x2', 'x3']}
In [61]: df.rename(columns=lambda c: d[c].pop(0) if c in d.keys() else c)
Out[61]:
a x1 x2 x3 z
0 6 2 7 7 8
1 6 6 3 1 1
2 6 6 7 5 6
3 8 3 6 1 8
4 5 7 5 3 0
这是另一个我认为更好的动态解决方案
In [59]: df
Out[59]:
a x x x z
0 6 2 7 7 8
1 6 6 3 1 1
2 6 6 7 5 6
3 8 3 6 1 8
4 5 7 5 3 0
In [61]: class renamer():
def __init__(self):
self.d = dict()
def __call__(self, x):
if x not in self.d:
self.d[x] = 0
return x
else:
self.d[x] += 1
return "%s_%d" % (x, self.d[x])
df.rename(columns=renamer())
Out[61]:
a x x_1 x_2 z
0 6 2 7 7 8
1 6 6 3 1 1
2 6 6 7 5 6
3 8 3 6 1 8
4 5 7 5 3 0
X_R.columns = ['Retail','Cost']
不是直接的答案,但由于这是热门搜索结果,因此这里有一个简短而灵活的解决方案,可以将后缀附加到重复的列名称:
# A dataframe with duplicated column names
df = pd.DataFrame([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
df.columns = ['a', 'b', 'b']
# Columns to not rename
excluded = df.columns[~df.columns.duplicated(keep=False)]
# An incrementer
import itertools
inc = itertools.count().__next__
# A renamer
def ren(name):
return f"{name}{inc()}" if name not in excluded else name
# Use inside rename()
df.rename(columns=ren)
a b b a b0 b1
0 1 2 3 0 1 2 3
1 4 5 6 => 1 4 5 6
2 7 8 8 2 7 8 9
MaxU 的回答帮助我解决了同样的问题。在这个答案中,我添加了一种方法来查找那些重复的列标题。
首先,我们创建重复列名的字典,其中的值与所需的新列名相对应。为此,需要 defaultdict 子类。
import pandas as pd
from collections import defaultdict
renamer = defaultdict()
我们迭代重复的列名以创建一个字典,其中键是重复的列名,值是新列名的列表。我选择此列表为原始名称_0、原始名称_1,依此类推。
for column_name in df.columns[df.columns.duplicated(keep=False)].tolist():
if column_name not in renamer:
renamer[column_name] = [column_name+'_0']
else:
renamer[column_name].append(column_name +'_'+str(len(renamer[column_name])))
print(renamer)
defaultdict(None, {'b': ['b_0', 'b_1', 'b_2', 'b_3'], 'c': ['c_0', 'c_1']})
原始数据框:
print(df)
a b b b b c c d
Item 0 2 1 0 2 8 3 9 5
Item 1 3 2 7 3 5 4 6 2
Item 2 4 3 8 1 5 7 4 4
Item 3 5 5 3 6 0 5 2 5
通过从我们的重命名器 defaultdict 中分配新名称来重命名重复的列,而保留不重复的列
df.rename(
columns=lambda column_name: renamer[column_name].pop(0)
if column_name in renamer
else column_name
)
a b_0 b_1 b_2 b_3 c_0 c_1 d
Item 0 2 1 0 2 8 3 9 5
Item 1 3 2 7 3 5 4 6 2
Item 2 4 3 8 1 5 7 4 4
Item 3 5 5 3 6 0 5 2 5
(作为旁注,有几个人质疑为什么首先存在重复的列名。就我自己而言,我在使用 xlwings 包导入时遇到了重复的列名(用于处理受密码保护的 Excel 文件)。您还可能通过使用
pd.concat
无意中创建重复的列名称。
对于OP问题中相对简单的情况,Mihkorz的答案效果很好。然而,对于动态重命名,还需要更多。有一些答案提供动态重命名。正如 @wjakobw 在 n49o7 的回答中的评论中指出的那样,
如果您有多组重复项,它们不会被独立处理。 a、a、b、b 变为 a0、a1、b2、b3。
gbitmmon 的答案避免了共享索引问题,Benedictanjw 的答案也是如此。后者具有用于管理重命名调用外部和内部重命名的代码。这个答案是提供与前者类似的动态重命名解决方案,但使用 collections.Counter 而不是手动跟踪添加的元素及其索引;并添加动态选择的分隔符而不是硬编码的
_
。
import pandas # Yes, I know the custom is to do `import pandas as pd`.
from collections import Counter
class ColumnRenamer:
def __init__(self, separator=None):
self.counter = Counter()
self.sep = separator
def __call__(self, x):
index = self.counter[x] # Counter returns 0 for missing elements
self.counter[x] = index + 1 # Uses something like `setdefault`
return f'{x}{self.sep if self.sep and index else ""}{index if index else ""}'
将此
DataFrame
与多个重复项、不同数量的重复项一起使用,并且并非全部都有重复项:
df = pandas.DataFrame(
[[0,1,2,4,3,2,1,4,2,1,0,2,3], [4,3,2,3,1,0,1,2,1,0,2,4,1], [1,2,3,2,1,3,0,4,1,2,2,3,1]],
columns=['x', 'x', 'q', 'y', 'y', 'z', 'z', 'x', 'z', 'z', 'z', 'z', 'x'],
)
df
Out[28]:
x x q y y z z x z z z z x
0 0 1 2 4 3 2 1 4 2 1 0 2 3
1 4 3 2 3 1 0 1 2 1 0 2 4 1
2 1 2 3 2 1 3 0 4 1 2 2 3 1
上面的
ColumnRenamer
类给出了完全唯一的列名,没有共享的重复索引,以及您想要的任何分隔符,包括空字符串:
df.rename(columns=ColumnRenamer(separator='#'))
Out[29]:
x x#1 q y y#1 z z#1 x#2 z#2 z#3 z#4 z#5 x#3
0 0 1 2 4 3 2 1 4 2 1 0 2 3
1 4 3 2 3 1 0 1 2 1 0 2 4 1
2 1 2 3 2 1 3 0 4 1 2 2 3 1
df.rename(columns=ColumnRenamer(separator='_'))
Out[30]:
x x_1 q y y_1 z z_1 x_2 z_2 z_3 z_4 z_5 x_3
0 0 1 2 4 3 2 1 4 2 1 0 2 3
1 4 3 2 3 1 0 1 2 1 0 2 4 1
2 1 2 3 2 1 3 0 4 1 2 2 3 1
df.rename(columns=ColumnRenamer(separator=''))
Out[31]:
x x1 q y y1 z z1 x2 z2 z3 z4 z5 x3
0 0 1 2 4 3 2 1 4 2 1 0 2 3
1 4 3 2 3 1 0 1 2 1 0 2 4 1
2 1 2 3 2 1 3 0 4 1 2 2 3 1
df.rename(columns=ColumnRenamer())
Out[32]:
x x1 q y y1 z z1 x2 z2 z3 z4 z5 x3
0 0 1 2 4 3 2 1 4 2 1 0 2 3
1 4 3 2 3 1 0 1 2 1 0 2 4 1
2 1 2 3 2 1 3 0 4 1 2 2 3 1