我有一个非常简单的需求已经出现在其他几篇文章中,但我不确定采用groupby
或duplicated
方法更好的方法。
我在duplicated
下面有我需要的内容,除了第一个副本被标记为FALSE
而不是TRUE
。我需要所有重复项为TRUE。
我的目标是能够在两个列重复时将两个列中的数据连接在一起,否则,将数据保持原样。
示例输入:
ID File Name
1 Text.csv
2 TEXT.csv
3 unique.csv
4 unique2.csv
5 text.csv
期望的输出:
ID File Name LowerFileName Duplicate UniqueFileName
1 Text.csv text.csv TRUE 1Text.csv
2 TEXT.csv text.csv TRUE 2TEXT.csv
3 unique.csv unique.csv FALSE unique.csv
4 unique2.csv unique2.csv FALSE unique2.csv
5 text.csv text.csv TRUE 5text.csv
df_attachment = pd.read_csv("Attachment.csv")
df_attachment['LowerFileName'] = df_attachment['File Name'].str.lower()
df_attachment['Duplicate'] = df_attachment.duplicated('LowerFileName')
#This syntax is incorrect
df_attachment['UniqueFileName'] = np.where(df_attachment['Duplicate']=='TRUE', pd.concat(df_attachment['ID'],df_attachment['File Name']), df_attachment['File Name'))
答案 0 :(得分:2)
“绕过”这个奇怪的Pandas功能的最简单方法是使用df.duplicated(col_name) | df.duplicated(col_name, take_last=True)
生成掩码。按位或表示您生成的系列对于所有重复项都是True
。
使用索引设置您从原始名称中获得的值或使用前面的数字设置新名称。
在下面的情况中:
# Generating your DataFrame
df_attachment = pd.DataFrame(index=range(5))
df_attachment['ID'] = [1, 2, 3, 4, 5]
df_attachment['File Name'] = ['Text.csv', 'TEXT.csv', 'unique.csv',
'unique2.csv', 'text.csv']
df_attachment['LowerFileName'] = df_attachment['File Name'].str.lower()
# Answer from here, mask generation over two lines for readability
mask = df_attachment.duplicated('LowerFileName')
mask = mask | df_attachment.duplicated('LowerFileName', take_last=True)
df_attachment['Duplicate'] = mask
# New column names if possible
df_attachment['number_name'] = df_attachment['ID'].astype(str) + df_attachment['File Name']
# Set the final unique name column using the mask already generated
df_attachment.loc[mask, 'UniqueFileName'] = df_attachment.loc[mask, 'number_name']
df_attachment.loc[~mask, 'UniqueFileName'] = df_attachment.loc[~mask, 'File Name']
# Drop the intermediate column used
del df_attachment['number_name']
最后df_attachment
:
ID File Name LowerFileName Duplicate UniqueFileName
0 1 Text.csv text.csv True 1Text.csv
1 2 TEXT.csv text.csv True 2TEXT.csv
2 3 unique.csv unique.csv False unique.csv
3 4 unique2.csv unique2.csv False unique2.csv
4 5 text.csv text.csv True 5text.csv
此方法使用矢量化pandas操作和索引,因此对于任何大小的DataFrame都应该快速。
昨天有人给了这个投票,所以我想我会编辑这个,说自0.17.0
以来大熊猫原生支持这一点,请看这里的变化:http://pandas.pydata.org/pandas-docs/version/0.19.2/whatsnew.html#v0-17-0-october-9-2015
现在,您可以使用keep
和drop_duplicates
的{{1}}参数,并将其设置为duplicated
以标记所有重复项:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.duplicated.html
因此,生成重复列的行变为:
False
答案 1 :(得分:1)
也许使用groupby
和lambda
表达式可以实现您的目标:
gb = df.groupby('Lower File Name')['Lower File Name'].count()
duplicates = gb[gb > 1].index.tolist()
df['UniqueFileName'] = \
df.apply(lambda x: '{0}{1}'.format(x.ID if x['Lower File Name'] in duplicates
else "", x['File Name']), axis=1)
>>> df
ID File Name Lower File Name Duplicate UniqueFileName
0 1 Text.csv text.csv False 1Text.csv
1 2 TEXT.csv text.csv True 2TEXT.csv
2 3 unique.csv unique.csv False 3unique.csv
3 4 unique2.csv unique2.csv False Noneunique2.csv
4 5 text.csv text.csv True 5text.csv
5 6 uniquE.csv unique.csv True 6uniquE.csv
lambda表达式根据OP的要求生成唯一的文件名,只有在File Name
重复的情况下(即有多个文件),才会将ID
与相关Lower File Name
前置。使用相同的小写文件名)。否则,它只使用不带ID
的小写文件名。
请注意,此解决方案不使用上述DataFrame中的Duplicate
列。
另外,简单地将ID
附加到Lower File Name
以生成唯一名称会不会更简单?假设ID是唯一的,您就不需要上面的解决方案,甚至不需要检查重复项。
答案 2 :(得分:0)
对于您的用例,您需要使用groupby:
dupes = df_attachment.groupby('Name').ID.count() > 1
dupes.name = 'Duplicate'
#merge duplicate flage into the original dataframe on the common column 'Name'
df_attachment = pd.merge(df_attachment, dupes.reset_index())
答案 3 :(得分:0)
受this answer启发(假设您的File Name
列已重命名为file_name
):
df['unique_name'] = df.file_name
dupes = df.file_name[df.file_name.str.lower().duplicated()]
unique_names = df.ID.astype(str) + df.file_name
df.loc[df.file_name.isin(dupes), 'unique_name'] = unique_names
这给了你:
ID File Name unique_name
0 1 Text.csv Text.csv
1 2 TEXT.csv 2TEXT.csv
2 3 unique.csv unique.csv
3 4 unique2.csv unique2.csv
4 5 text.csv 5text.csv