Pandas的DataFrame - 重命名多个相同名称的列
我在一个数据表(df)里有好几个名字一样的列。我想给它们改名字,但问题是用 df.rename
这个方法改名字的时候,所有的列都会被改成一样的名字。我该怎么把下面这些名字改成 blah1、blah4、blah5 呢?
df = pd.DataFrame(np.arange(2*5).reshape(2,5))
df.columns = ['blah','blah2','blah3','blah','blah']
df
# blah blah2 blah3 blah blah
# 0 0 1 2 3 4
# 1 5 6 7 8 9
这是使用 df.rename
方法时发生的情况:
df.rename(columns={'blah':'blah1'})
# blah1 blah2 blah3 blah1 blah1
# 0 0 1 2 3 4
# 1 5 6 7 8 9
14 个回答
4
我刚写了这段代码,它使用了一种叫做列表推导的方法来更新所有重复的名字。
df.columns = [x[1] if x[1] not in df.columns[:x[0]] else f"{x[1]}_{list(df.columns[:x[0]]).count(x[1])}" for x in enumerate(df.columns)]
4
你可以直接给列赋值:
In [12]:
df.columns = ['blah','blah2','blah3','blah4','blah5']
df
Out[12]:
blah blah2 blah3 blah4 blah5
0 0 1 2 3 4
1 5 6 7 8 9
[2 rows x 5 columns]
如果你想动态地重命名重复的列,可以参考下面的做法(这段代码来自答案2:Python列表中重复项的索引):
In [25]:
import collections
dups = collections.defaultdict(list)
dup_indices=[]
col_list=list(df.columns)
for i, e in enumerate(list(df.columns)):
dups[e].append(i)
for k, v in sorted(dups.items()):
if len(v) >= 2:
dup_indices = v
for i in dup_indices:
col_list[i] = col_list[i] + ' ' + str(i)
col_list
Out[25]:
['blah 0', 'blah2', 'blah3', 'blah 3', 'blah 4']
然后你可以用这个方法重新赋值,你也可以写一个函数来生成一个在重命名之前不重复的唯一名称。
13
你可以使用这个:
def df_column_uniquify(df):
df_columns = df.columns
new_columns = []
for item in df_columns:
counter = 0
newitem = item
while newitem in new_columns:
counter += 1
newitem = "{}_{}".format(item, counter)
new_columns.append(newitem)
df.columns = new_columns
return df
然后
import numpy as np
import pandas as pd
df=pd.DataFrame(np.arange(2*5).reshape(2,5))
df.columns=['blah','blah2','blah3','blah','blah']
这样df:
blah blah2 blah3 blah blah
0 0 1 2 3 4
1 5 6 7 8 9
接着
df = df_column_uniquify(df)
这样df:
blah blah2 blah3 blah_1 blah_2
0 0 1 2 3 4
1 5 6 7 8 9
39
从Pandas 0.19.0开始,pd.read_csv()
对重复列名的支持得到了改善
所以我们可以尝试使用内部方法:
In [137]: pd.io.parsers.ParserBase({'names':df.columns})._maybe_dedup_names(df.columns)
Out[137]: ['blah', 'blah2', 'blah3', 'blah.1', 'blah.2']
自Pandas 1.3.0起:
pd.io.parsers.base_parser.ParserBase({'names':df.columns, 'usecols':None})._maybe_dedup_names(df.columns)
这是一个“魔法”函数:
def _maybe_dedup_names(self, names):
# see gh-7160 and gh-9424: this helps to provide
# immediate alleviation of the duplicate names
# issue and appears to be satisfactory to users,
# but ultimately, not needing to butcher the names
# would be nice!
if self.mangle_dupe_cols:
names = list(names) # so we can index
counts = {}
for i, col in enumerate(names):
cur_count = counts.get(col, 0)
if cur_count > 0:
names[i] = '%s.%d' % (col, cur_count)
counts[col] = cur_count + 1
return names
36
我想在Pandas里找到一个解决方案,而不是用一般的Python方法。列的get_loc()函数会返回一个带掩码的数组,如果发现重复项,它会用'True'标记出重复项的位置。然后我可以用这个掩码来给这些位置赋新值。在我的情况下,我事先知道会有多少个重复项,以及我想给它们赋什么值,但看起来df.columns.get_duplicates()会返回所有重复项的列表,如果你需要更通用的去重操作,可以结合这个列表和get_loc()来使用。
'''截至2020年9月更新'''
cols=pd.Series(df.columns)
for dup in df.columns[df.columns.duplicated(keep=False)]:
cols[df.columns.get_loc(dup)] = ([dup + '.' + str(d_idx)
if d_idx != 0
else dup
for d_idx in range(df.columns.get_loc(dup).sum())]
)
df.columns=cols
blah blah2 blah3 blah.1 blah.2
0 0 1 2 3 4
1 5 6 7 8 9
更好的新方法(更新于2019年12月3日)
下面的代码比上面的代码更好。是从下面的另一个答案中复制过来的(@SatishSK):
#sample df with duplicate blah column
df=pd.DataFrame(np.arange(2*5).reshape(2,5))
df.columns=['blah','blah2','blah3','blah','blah']
df
# you just need the following 4 lines to rename duplicates
# df is the dataframe that you want to rename duplicated columns
cols=pd.Series(df.columns)
for dup in cols[cols.duplicated()].unique():
cols[cols[cols == dup].index.values.tolist()] = [dup + '.' + str(i) if i != 0 else dup for i in range(sum(cols == dup))]
# rename the columns with the cols list.
df.columns=cols
df
输出:
blah blah2 blah3 blah.1 blah.2
0 0 1 2 3 4
1 5 6 7 8 9