パンダの重複行のリストを取得するにはどうすればよいですか?
358個のサンプルに10万を超える変数(行)があるビッグデータフレームがあります。
すべてのサンプルでどの変数が同一(重複)であるかを知りたいです。
サンプルデータフレームは次のようなものです。
Sample1 Sample2 Sample3 Sample4 Sample5
1000084 0.0 0.0 0.0 0.0 0.0
1000092 0.0 0.0 0.0 0.0 0.0
1000096 0.0 0.0 1.0 0.0 0.0
1000110 0.0 0.0 1.0 0.0 0.0
1000116 0.0 0.0 0.0 0.0 0.0
必要な結果は次のようになります:または同一の行のリストのリスト
{1000084:[1000092, 1000116], 1000096:[1000110]}
パンダから複製方法を試しましたが、一意のアイテムまたは一意のアイテムと最初または最後の複製のみが残ります。
私はこのコードで試しましたが、時間がかかっています:
duplicated_index = set()
duplicates = {}
for i, pos in enumerate(df.index, 0):
#check if the row has marked as duplicate, if so, ignore it
if i in duplicated_index:
continue
for j in range(i+1, df.shape[0]):
if all(df.iloc[i] == df.iloc[j]):
duplicated_index.add(j)
tmp = duplicates.setdefault(pos, [])
duplicates[pos].append(df.iloc[j].name)
このリストを取得し、どの行が他の行と同一であるかを識別するためのより適切な方法はありますか?
回答
すべての列でグループ化します。複数のアイテムを持つグループを見つけて、それらをリストに入れます。forループを使用します。
>>> gb = df.groupby(df.columns.to_list())
>>> d = {}
>>> for a,b in gb:
... if len(b) > 1:
... d[b.index[0]] = b.index[1:].to_list()
>>> d
{1000084: [1000092, 1000116], 1000096: [1000110]}
>>>
上記と同じgroupbyを使用して、グループのインデックスを返す関数を記述し、aggregateメソッドを使用して辞書を作成します。
def f(thing):
return thing.index.to_list()
>>> {key:val for key,*val in gb.aggregate(f) if val}
{1000084: [1000092, 1000116], 1000096: [1000110]}
この実行時間は、列と行の数(アイテムの数)に比例して変化するように見えます。
これがテスト用の大きなDataFrameです。残念ながら、重複する行を生成することは望んでいません-おそらくそれはgroupbyにとって最悪のケースであり、それから繰り返しますか?
import itertools,string
import numpy as np
nrows,ncols = 100000,300
a = np.random.randint(1,3,(nrows,ncols))
# or using the new random stuff
#from numpy.random import default_rng
#rng = default_rng()
#a = rng.integers(1,3,(nrows,ncols))
index = np.arange(1000000,1000000+nrows,dtype=np.int64)
cols = [''.join(thing) for thing in itertools.combinations(string.ascii_letters,3)]
df2 = pd.DataFrame(data=a,index=index,columns=cols[:ncols])
reset_index
次にgroupby
追加しますagg
l = df.reset_index().groupby(list(df))['index'].agg(list).tolist()
Out[291]: [[1000084, 1000092, 1000116], [1000096, 1000110]]
pandas
duplicated()
重複したすべての行を返す独自の関数があります。
duplicated_rows = df[df.duplicated(subset=['col1', 'col2', 'col3'], keep=False)]
ドキュメントによると、
subset
重複をチェックする必要がある選択した列のリストにすることができます。デフォルトでは、すべての列を使用します。keep
すべての発生False
を保持するように設定されています。
結果をリストのリストとして表示したい場合は、上記でドラフトしたコードを少し変更するだけで問題が解決する可能性があります。
pd.factorize
およびで別のアプローチを追加するIndex.groupby
idx = pd.factorize(list(map(tuple,df.to_numpy().tolist())))[0]
d = {g[0]: [*g[1:]] for _,g in df.index.groupby(idx).items() if len(g)>1}
{1000084: [1000092, 1000116], 1000096: [1000110]}
またはを使用しますdf.to_records()
が、前の方法よりも遅くなる可能性があります。
idx = pd.factorize(df.to_records(index=False))[0]
d = {g[0]: [*g[1:]] for _,g in df.index.groupby(idx).items() if len(g)>1}