我已经搜索了很多,但是似乎没有任何解决方法。
假设df
何时:
import pandas as pd
import numpy as np
df = pd.DataFrame([['a','b','c'], ['a',np.nan,'b'], [np.nan, 'b', 'a'], ['a', 'd', 'b']])
df
0 1 2
0 a b c
1 a NaN b
2 NaN b a
3 a d b
所需的输出是:
0 1 2
0 a b c
3 a d b
第1行,第2行是第0行的子集,因此我想删除它们。在检查某行是否是其他任何子集时,不考虑NaN
。因此,第1行变成{'a','b'}
,从而成为子集。
到目前为止,我一直在尝试制作set
s:
df.ffill(1).bfill(1).apply(set, 1)
产生:
0 {c, a, b}
1 {a, b}
2 {a, b}
3 {d, a, b}
但是我被困在这里。 pd.DataFrame.drop_duplicates
似乎对我没有帮助。
非常感谢您的帮助:)
答案 0 :(得分:4)
这很难。理想情况下,您希望:
pd.Index
,它的行为就像一个集合,并且具有一些类似于集合操作的方法。)由于特定的条件,在这两种方法中都很难做到,并且时间复杂度可能因此变得很繁琐。 (我不排除答案可能比这个答案更模糊。)但是通常,一旦您从精确重复的测试转到子集测试,事情就会变得更加困难。
所有这些,您可以:
set.issuperset
调用中使用any()
来查找重复的索引,以利用frozenset
是可哈希的事实(由于这里的其他答案)。复杂度仍然是N ^ 2或接近它,但是对于中等大小的数据,这可能就足够了。
>>> df = pd.DataFrame([['a','b','c'], ['a',np.nan,'b'], [np.nan, 'b', 'a'], ['a', 'd', 'b']])
>>>
>>> seen = set()
>>> add = seen.add
>>> dupes = []
>>>
>>> for pos, row in enumerate(df.values.tolist()):
... vals = frozenset(i for i in row if isinstance(i, str))
... if any(i.issuperset(vals) for i in seen):
... dupes.append(pos)
... add(vals)
...
>>> dupes
[1, 2]
这使您可以通过DataFrame.drop()
删除索引。
答案 1 :(得分:2)
您可以使用frozenset
代替set
。
import pandas as pd
import numpy as np
def remove_myself_from_dict(some_dict, myself):
_some_dict = some_dict.copy()
_ = _some_dict.pop(myself)
return _some_dict
df = pd.DataFrame([['a','b','c'], ['a',np.nan,'b'], [np.nan, 't', 'a'], ['a', 'd', 'b']])
df['column_set'] = df.ffill(1).bfill(1).apply(frozenset, 1)
all_set = dict(zip(df['column_set'], range(len(df))))
df['is_subset'] = df['column_set'].apply(
lambda x: any([some_set >= x for some_set in remove_myself_from_dict(all_set, x)])
)
结果df
将
0 1 2 column_set is_subset
0 a b c (b, c, a) False
1 a NaN b (b, a) True
2 NaN t a (t, a) False
3 a d b (b, d, a) False