Pandas复制vs groupby以标记所有重复值

时间:2015-06-24 03:38:11

标签: python pandas

我有一个非常简单的需求已经出现在其他几篇文章中,但我不确定采用groupbyduplicated方法更好的方法。

我在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'))

4 个答案:

答案 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都应该快速。

编辑:2017-03-28

昨天有人给了这个投票,所以我想我会编辑这个,说自0.17.0以来大熊猫原生支持这一点,请看这里的变化:http://pandas.pydata.org/pandas-docs/version/0.19.2/whatsnew.html#v0-17-0-october-9-2015

现在,您可以使用keepdrop_duplicates的{​​{1}}参数,并将其设置为duplicated以标记所有重复项:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.duplicated.html

因此,生成重复列的行变为:

False

答案 1 :(得分:1)

也许使用groupbylambda表达式可以实现您的目标:

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