如果一列不同,则删除pandas数据框中的重复项,但是在给定列表中

时间:2017-04-07 09:45:34

标签: python pandas dataframe duplicates

我有一个来自两个来源的重复条目的数据框,所有值都应该是唯一的,但是一列的格式不同,因此我应该在一列中删除具有不同名称的副本,但仅当名称在一个清单。

从技术上讲,如果存在另一行具有相同AB值的行,我想删除pandas数据框中的行,但仅当此行的Z值为{时{1}}和另一个' Z'是'bar'

示例可能更清晰:

我有给定的数据框'foo'

df

我想得到

 A     B     Z

'a'   'a'   'foo'
'a'   'a'   'bar'
'b'   'a'   'bar'
'c'   'c'   'foo'
'd'   'd'   'blb'

请注意:

  • 不应触及 A B Z 'a' 'a' 'foo' 'b' 'a' 'bar' 'c' 'c' 'foo' 'd' 'd' 'blb' 列中除'foo''bar'以外的其他值的行。
  • 如果Z'foo'保持不变,这一点并不重要,因为之后它们会更改为相同的值。
  • 将二人组'bar''foo'概括为一个列表会很棒。

到目前为止尝试: 这是我最好的猜测,它虽然不起作用...我不太了解groupby返回的内容。此外,我确信有一些神奇的大熊猫单线,我找不到。

'bar'

谢谢!

2 个答案:

答案 0 :(得分:1)

我认为你可以通过连接原始数据帧的两个子集来获得预期的结果:

  • 其中Z值既不是foo也不是bar
  • 和另一个根据AB重复的内容

这是一个给出预期输出的例子:

data = """ A     B     Z
a   a   foo
a   a   bar
b   a   bar
c   c   foo
d   d   blb"""
df = pd.read_csv(StringIO(data),sep='\s+')

ls = ['foo','bar']
df1 = pd.concat((df.loc[~(df.Z.isin(ls))], # no foos or bars here
                 df.loc[  df.Z.isin(ls)].drop_duplicates(subset=['A','B'])
                 )).sort_index()

更简单的选项可能是在foo中的bar替换Z,然后只删除重复项:

df1 = df.replace({'Z':{'foo':'bar'}}).drop_duplicates()

您甚至可以将foobar替换为您实际要使用的其他值:

df1 = df.replace({'Z':{'foo':'xyz', 'bar':'xyz'}}).drop_duplicates()

答案 1 :(得分:0)

我会使用groupby来模拟检查重复项(正如您所想的那样)。相反,您将对AB进行分组,然后使用每个单独的分组DF来检查foobar是否在Z

import pandas as pd

df = pd.DataFrame()
df['A'] = ['a', 'a', 'b', 'c', 'd']
df['B'] = ['a', 'a', 'a', 'c', 'd']
df['Z'] = ['foo', 'bar', 'bar', 'foo', 'blib']

VALUES_PRESENT_TO_DROP = ['foo', 'bar']

# Simulate `df.duplicated, keep=False`
grouped = df.groupby(['A', 'B'])

# Start a list of the final DFs to keep, will append to this
dfs_to_keep = []

# PLEASE SEE EDIT BELOW
# We're not interested in the values of thr group, just each df
for _, grouped_df in grouped:
    values_in_col = grouped_df['Z'].unique()
    # Check that all the required values to drop are present
    if all((val in values_in_col for val in VALUES_PRESENT_TO_DROP)):
        # Append just the first row
        dfs_to_keep.append(grouped_df.iloc[[0]])
    else:
        dfs_to_keep.append(grouped_df)

# Combine all into final, deduped DF
df_final = pd.concat(dfs_to_keep).sort_index()

df_final
   A  B     Z
0  a  a   foo
2  b  a   bar
3  c  c   foo
4  d  d  blib

编辑:刚刚意识到这一行:“不应触及Z列中除'foo'和'bar'之外的其他值的行。”

此修改需要对逻辑进行一些更改。请参阅下面的插槽:

# We're not interested in the values of the group, just each df
for _, grouped_df in grouped:
    mask_possibly_edit = grouped_df['Z'].isin(VALUES_PRESENT_TO_DROP)
    # Always keep those that do not have the specified valued in `Z`
    dfs_to_keep.append(grouped_df[~mask_possibly_edit])

    df_possibly_dedupe = grouped_df[mask_possibly_edit]
    values_in_col = df_possibly_dedupe['Z'].unique()
    # Check that all the required values to drop are present
    if all((val in values_in_col for val in VALUES_PRESENT_TO_DROP)):
        # Append just the first row
        dfs_to_keep.append(df_possibly_dedupe.iloc[[0]])
    else:
        dfs_to_keep.append(df_possibly_dedupe)