繁体   English   中英

如何从另一个 dataframe 中删除一个 pandas dataframe

[英]How to remove a pandas dataframe from another dataframe

如何从另一个 dataframe 中删除一个 pandas dataframe,就像集合减法一样:

a=[1,2,3,4,5]
b=[1,5]
a-b=[2,3,4]

现在我们有两个 pandas dataframe,如何从 df1 中删除 df2:

In [5]: df1=pd.DataFrame([[1,2],[3,4],[5,6]],columns=['a','b'])
In [6]: df1
Out[6]:
   a  b
0  1  2
1  3  4
2  5  6


In [9]: df2=pd.DataFrame([[1,2],[5,6]],columns=['a','b'])
In [10]: df2
Out[10]:
   a  b
0  1  2
1  5  6

然后我们期望 df1-df2 结果将是:

In [14]: df
Out[14]:
   a  b
0  3  4

怎么做?

谢谢你。

解决方案

使用pd.concat后跟drop_duplicates(keep=False)

pd.concat([df1, df2, df2]).drop_duplicates(keep=False)

看起来像

   a  b
1  3  4

说明

pd.concat通过一个接一个地附加来将两个DataFrame相加。 如果有任何重叠,它将被drop_duplicates方法捕获。 但是,默认情况下drop_duplicates第一个观察结果并删除所有其他观察结果。 在这种情况下,我们希望删除所有重复项。 因此, keep=False参数正是这样做的。

对重复的df2特别说明。 只有一个df2 df2不在df1任何行都不会被视为重复并将保留。 这个只有一个df2解决方案仅在df2df1的子集时才有效。 但是,如果我们连接df2两次,它肯定是重复的,随后将被删除。

您可以使用.duplicated ,它的好处是具有相当的表现力:

%%timeit
combined = df1.append(df2)
combined[~combined.index.duplicated(keep=False)]

1000 loops, best of 3: 875 µs per loop

比较:

%timeit df1.loc[pd.merge(df1, df2, on=['a','b'], how='left', indicator=True)['_merge'] == 'left_only']

100 loops, best of 3: 4.57 ms per loop


%timeit pd.concat([df1, df2, df2]).drop_duplicates(keep=False)

1000 loops, best of 3: 987 µs per loop


%timeit df2[df2.apply(lambda x: x.value not in df2.values, axis=1)]

1000 loops, best of 3: 546 µs per loop

总之,使用np.array比较是最快的。 那里不需要.tolist()

一套逻辑方法。 df1df2的行变成集合。 然后使用set减法定义新的DataFrame

idx1 = set(df1.set_index(['a', 'b']).index)
idx2 = set(df2.set_index(['a', 'b']).index)

pd.DataFrame(list(idx1 - idx2), columns=df1.columns)

   a  b
0  3  4

我从问题中对合并 df1 和 df2 进行了拍摄。

使用“指标”参数

In [74]: df1.loc[pd.merge(df1, df2, on=['a','b'], how='left', indicator=True)['_merge'] == 'left_only']
Out[74]: 
   a  b
1  3  4

当您的df_to_drop是 main data frame data的子集时,此解决方案有效。

data_clean = data.drop(df_to_drop.index)

一种掩蔽方法

df1[df1.apply(lambda x: x.values.tolist() not in df2.values.tolist(), axis=1)]

   a  b
1  3  4

获取包含 DF1 但不在 DF2 中的所有记录的数据框

DF=DF1[~DF1.isin(DF2)].dropna(how = 'all')

我认为第一个tolist()需要删除,但保留第二个:

df1[df1.apply(lambda x: x.values() not in df2.values.tolist(), axis=1)]

最简单的选择是使用索引。

  1. 附加 df1 和 df2 并重置它们的索引。

    df = df1.concat(df2)
    df.reset_index(inplace=True)

  2. 例如:
    这将给出 df2 索引

    indexes_df2 = df.index[ (df["a"].isin(df2["a"]) ) & (df["b"].isin(df2["b"]) ) result_index = df.index[~index_df2] result_data = df.iloc[ result_index,:]

希望它对新读者有所帮助,尽管这个问题是在不久前发布的:)

如果df1包含重复项 + 保留索引的解决方案。

piRSquared答案的修改版本保留df1中没有出现在df2中的重复项,同时维护索引。

df1[df1.apply(lambda x: (x == pd.concat([df1.drop_duplicates(), df2, df2]).drop_duplicates(keep=False)).all(1).any(), axis=1)]

如果你的数据框很大,你可能想要存储结果

pd.concat([df1.drop_duplicates(), df2, df2]).drop_duplicates(keep=False)

df1.apply调用之前的变量中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM