データフレームに入ったデータについて、重複がないか確認したい場面は結構あると思います。
僕の場合は、そういう時はSQLでデータを抽出する段階でユニークにしてしまうことが多いです。
また、特定の列の値(idなど)の一意性の確認であれば、value_counts()して、2個以上含まれている値が無いか見たりします。
それ以外のケースでも、groupbyやsetなど使ってゴリゴリコードを書いてどうにかすることが多いのですが、
せっかく専用の関数が用意されているので今後はそれを使うようにしたいです。
ということで、今回はduplicated()
の紹介です。
ドキュメントはこちら。
pandas.DataFrame.duplicated
pythonを勉強し始めた頃、引数なしで実行して、
出力が直感的でなくて使いにくいなーと思っていたのですが、subsetやkeepなどの引数をきちんと理解すれば非常に便利です。
とりあえず実験するために、ダミーデータを作っておきます。
import pandas as pd
import numpy as np
df = pd.DataFrame(
{
"col0": np.random.choice(["A", "B", "C"], size=10),
"col1": np.random.choice(["a", "b", "c"], size=10),
"col2": np.random.choice(["1", "2", "3"], size=10),
}
)
print(df)
'''
出力 (乱数を使っているので実行するたびに変わります。)
col0 col1 col2
0 B b 1
1 C c 2
2 A b 1
3 B a 2
4 A b 1
5 C b 3
6 A b 1
7 B b 1
8 A b 3
9 B b 3
'''
このデータフレームに対して、引数無しで実行したものがこちらです。
print(df.duplicated())
'''
0 False
1 False
2 False
3 False
4 True
5 False
6 True
7 True
8 False
9 False
dtype: bool
'''
これ、一見、インデックス4,5,6の行が重複してるという意味に勘違いしそうなのですがそうではありません。
引数を省略すると、keep="first"
を指定したことになり、重複行のうち、最初の値はFalseになります。
なので、インデックス4の行と重複してる行が0~3の間にあるという意味です。(実際はインデックス2)
keep="last"
を指定すると、逆に重複している行のうち、
最後の行はFalse、それ以外の行はTrueになります。(重複してない行はFalse)
こちらの方が、時系列に並べたデータのうち、最新のデータを取りたい場面などで重宝すると思います。
また、 subsetに列名の集合を渡すと、その列だけを使って判定を行います。
これもまとめて試してみましょう。
print(df.duplicated(subset=["col1", "col2"], keep="last"))
'''
0 True
1 False
2 True
3 False
4 True
5 True
6 True
7 False
8 True
9 False
dtype: bool
'''
重複した行全部を抽出したい、という場合は、keep=False
を指定します。
また、先に紹介した2例でもそうなのですが、実際に使う時は重複した行のインデックスではなくて、
その行そのものをみたいという場面が多いので、次のような使い方になると思います。
print(df[df.duplicated(subset=["col1", "col2"], keep=False)])
'''
col0 col1 col2
0 B b 1
2 A b 1
4 A b 1
5 C b 3
6 A b 1
7 B b 1
8 A b 3
9 B b 3
'''
df[]
の中に放り込んであげるだけですね。
コードのテスト時など、無いはずの重複が本当に無いことを確認する時などは、
duplicated
関数は結構便利です。
重複を除外する時などはまた専用の関数があるので次に紹介します。