一个简单的熊猫问题:
是否有drop_duplicates()
功能可以删除复制中涉及的每一行?
一个等效的问题如下:pandas对数据帧有不同的设置吗?
例如:
In [5]: df1 = pd.DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})
In [6]: df2 = pd.DataFrame({'col1':[4,2,5], 'col2':[6,3,5]})
In [7]: df1
Out[7]:
col1 col2
0 1 2
1 2 3
2 3 4
In [8]: df2
Out[8]:
col1 col2
0 4 6
1 2 3
2 5 5
所以像df2.set_diff(df1)
这样的东西会产生这个:
col1 col2
0 4 6
2 5 5
但是,我不想依赖索引,因为在我的情况下,我必须处理具有不同索引的数据帧。
顺便说一下,我最初考虑过当前drop_duplicates()
方法的扩展,但现在我意识到使用集合论属性的第二种方法通常会更有用。但是,这两种方法都解决了我当前的问题。
谢谢!
答案 0 :(得分:38)
比特复杂,但如果你想完全忽略索引数据。将数据帧的内容转换为包含列的元组集:
ds1 = set([tuple(line) for line in df1.values])
ds2 = set([tuple(line) for line in df2.values])
此步骤也将删除数据框中的任何重复项(忽略索引)
set([(1, 2), (3, 4), (2, 3)]) # ds1
然后可以使用set方法查找任何内容。例如,找出差异:
ds1.difference(ds2)
给出: set([(1,2),(3,4)])
如果需要,可以将其恢复为数据帧。注意必须将set转换为list 1st,因为set不能用于构造dataframe:
pd.DataFrame(list(ds1.difference(ds2)))
答案 1 :(得分:24)
from pandas import DataFrame
df1 = DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})
df2 = DataFrame({'col1':[4,2,5], 'col2':[6,3,5]})
print df2[~df2.isin(df1).all(1)]
print df2[(df2!=df1)].dropna(how='all')
print df2[~(df2==df1)].dropna(how='all')
答案 2 :(得分:18)
这是另一个保留索引的答案,并且在两个数据框中不需要相同的索引。
pd.concat([df2, df1, df1]).drop_duplicates(keep=False)
速度快,结果
col1 col2
0 4 6
2 5 5
答案 3 :(得分:4)
按要映射的对象的列应用(df2);找到不在集合中的行(isin
就像集合运算符)
In [32]: df2.apply(lambda x: df2.loc[~x.isin(df1[x.name]),x.name])
Out[32]:
col1 col2
0 4 6
2 5 5
同样的事情,但是包括df1中的所有值,但仍然是df2中的每列
In [33]: df2.apply(lambda x: df2.loc[~x.isin(df1.values.ravel()),x.name])
Out[33]:
col1 col2
0 NaN 6
2 5 5
第二个例子
In [34]: g = pd.DataFrame({'x': [1.2,1.5,1.3], 'y': [4,4,4]})
In [35]: g.columns=df1.columns
In [36]: g
Out[36]:
col1 col2
0 1.2 4
1 1.5 4
2 1.3 4
In [32]: g.apply(lambda x: g.loc[~x.isin(df1[x.name]),x.name])
Out[32]:
col1 col2
0 1.2 NaN
1 1.5 NaN
2 1.3 NaN
注意,在0.13中,帧级别上会有一个isin
运算符,因此应该可以:df2.isin(df1)
答案 4 :(得分:3)
获取合并的交集索引,然后删除它们:
>>> df_all = pd.DataFrame(np.arange(8).reshape((4,2)), columns=['A','B']); df_all
A B
0 0 1
1 2 3
2 4 5
3 6 7
>>> df_completed = df_all.iloc[::2]; df_completed
A B
0 0 1
2 4 5
>>> merged = pd.merge(df_all.reset_index(), df_completed); merged
index A B
0 0 0 1
1 2 4 5
>>> df_pending = df_all.drop(merged['index']); df_pending
A B
1 2 3
3 6 7
答案 5 :(得分:3)
有3种方法可行,但其中有两种方法存在缺陷。
方法1(哈希方法):
它适用于我测试的所有案例。
@ProcedureName
方法2(Dict方法):
如果DataFrames包含datetime列,则会失败。
df1.loc[:, "hash"] = df1.apply(lambda x: hash(tuple(x)), axis = 1)
df2.loc[:, "hash"] = df2.apply(lambda x: hash(tuple(x)), axis = 1)
df1 = df1.loc[~df1["hash"].isin(df2["hash"]), :]
方法3(MultiIndex方法):
我在使用None或NaN的列失败时遇到了这种情况。
df1 = df1.loc[~df1.isin(df2.to_dict(orient="list")).all(axis=1), :]
答案 6 :(得分:2)
假设:
- df1和df2具有相同的列
- 这是一个设置操作,因此忽略重复项
- 集合不是非常大,所以你不用担心内存
醇>
union = pd.concat([df1,df2])
sym_diff = union[~union.duplicated(keep=False)]
union_of_df1_and_sym_diff = pd.concat([df1, sym_diff])
diff = union_of_df1_and_sym_diff[union_of_df1_and_sym_diff.duplicated()]
答案 7 :(得分:1)
我不确定pd.concat()
如何隐式加入重叠列,但我不得不对@radream的答案进行一些调整。
从概念上讲,多列上的集合差异(symmetric)是集合并(外部联接)减去集合交集(或内部联接):
df1 = pd.DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})
df2 = pd.DataFrame({'col1':[4,2,5], 'col2':[6,3,5]})
o = pd.merge(df1, df2, how='outer')
i = pd.merge(df1, df2)
set_diff = pd.concat([o, i]).drop_duplicates(keep=False)
这会产生:
col1 col2
0 1 2
2 3 4
3 4 6
4 5 5
答案 8 :(得分:1)
Pandas MultiIndex对象具有作为方法实现的快速设置操作,因此您可以将DataFrames转换为MultiIndexes,使用difference()
方法,然后将结果转换回DataFrame。该解决方案应该比到目前为止给出的解决方案要快得多(从我的简要测试中得出的结果约为100倍或更多),并且它不依赖于原始帧的行索引。正如皮奥特(Piotr)为他的回答所提到的那样,由于np.nan!= np.nan,这将以空值失败。 df2中具有空值的任何行将始终出现在差异中。另外,两个DataFrame的列顺序应相同。
df1mi = pd.MultiIndex.from_arrays(df1.values.transpose(), names=df1.columns)
df2mi = pd.MultiIndex.from_arrays(df2.values.transpose(), names=df2.columns)
dfdiff = df2mi.difference(df1mi).to_frame().reset_index(drop=True)
答案 9 :(得分:1)
Numpy的setdiff1d可以工作并且可能更快。
对于每一列:
np.setdiff1(df1.col1.values, df2.col1.values)
类似这样:
setdf = pd.DataFrame({
col: np.setdiff1d(getattr(df1, col).values, getattr(df2, col).values)
for col in df1.columns
})
答案 10 :(得分:0)
即使两个数据框中都有多个列,这也应该起作用。但是请确保两个数据框的列名完全相同。
set_difference = pd.concat([df2, df1, df1]).drop_duplicates(keep=False)
对于多列,您还可以使用:
col_names=['col_1','col_2']
set_difference = pd.concat([df2[col_names], df1[col_names],
df1[col_names]]).drop_duplicates(keep=False)