Python 如果一列不同但在给定列表中,则删除数据帧中的重复项
我有一个数据框,其中有来自两个源的重复条目,所有值都应该是唯一的,但有一列的格式不同,因此我应该删除一列中具有不同名称的重复项,但仅当名称在列表中时 从技术上讲,如果存在具有相同Python 如果一列不同但在给定列表中,则删除数据帧中的重复项,python,pandas,dataframe,duplicates,Python,Pandas,Dataframe,Duplicates,我有一个数据框,其中有来自两个源的重复条目,所有值都应该是唯一的,但有一列的格式不同,因此我应该删除一列中具有不同名称的重复项,但仅当名称在列表中时 从技术上讲,如果存在具有相同a和B值的另一行,但仅当这一行的Z值为'bar'而另一行的'Z'为'foo'时,我希望删除pandas数据帧中的一行 一个例子可能更清楚: 我有给定的数据帧df A B Z 'a' 'a' 'foo' 'a' 'a' 'bar' 'b' 'a' 'bar' 'c' 'c'
a
和B
值的另一行,但仅当这一行的Z
值为'bar'
而另一行的'Z'为'foo'
时,我希望删除pandas数据帧中的一行
一个例子可能更清楚:
我有给定的数据帧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'
请注意:
- 不应触摸
列中除Z
和'foo'
以外的值的行'bar'
- 如果
和'foo'
保持不变,这并不重要,因为它们将在以后更改为相同的值'bar'
- 将这两个“foo”和“bar”概括为一个列表会很好
new_df = []
for row in df.groupby('A'):
if rowloc['Z'].isin('foo'):
if not row['Z'].isin('bar'):
new_df.append(row)
谢谢 我认为您可以通过连接原始数据帧的两个子集来获得预期的结果:
- Z值既不是
也不是foo
bar
- 另一个是根据
和A
删除重复项B
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()
一个更简单的选择可能是用Z
中的bar
替换foo
,然后简单地删除重复项:
df1 = df.replace({'Z':{'foo':'bar'}}).drop_duplicates()
您甚至可以用实际要使用的其他值替换foo
和bar
:
df1 = df.replace({'Z':{'foo':'xyz', 'bar':'xyz'}}).drop_duplicates()
我会使用
groupby
来模拟检查重复项(如您所想)。而是将A
和B
分组,然后与每个单独分组的DF一起检查foo
和bar
是否在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)
可能重复以上答案是更好的顺便说一句,没有不必要的分组!不过感谢您花时间,我还是从您的示例中学到了一些功能:)不客气,(由
drop\u duplicates使用)函数通常非常有用。如果一行是重复的,则可以生成一个布尔值
序列。可以使用子集(如上所述),并且可以选择不将第一个/最后一个实例标记为重复,或者只标记全部。非常感谢,我没有意识到您可以使用子集来使用drop\u重复。祝你有愉快的一天。