重命名 Pandas 数据框中具有重复列名的列?

问题描述 投票:0回答:6

我有一个 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"})

只给我两列名为“成本”的列。

在这种情况下如何重命名列?

python pandas
6个回答
28
投票

这是一个动态解决方案:

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

24
投票

这是另一个我认为更好的动态解决方案

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

19
投票
X_R.columns = ['Retail','Cost']

7
投票

不是直接的答案,但由于这是热门搜索结果,因此这里有一个简短而灵活的解决方案,可以将后缀附加到重复的列名称:

# 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

5
投票

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
无意中创建重复的列名称。


0
投票

对于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
© www.soinside.com 2019 - 2024. All rights reserved.