- 1 1. はじめに
- 2 2. Pythonで重複要素を削除する基本3パターン
- 3 3. 要素がリストなど「非ハッシュable」の場合の処理
- 4 4. 応用編:重複のみ抽出 or 出現回数カウント
- 5 5. Pandas DataFrameにおける重複削除
- 6 6. パフォーマンス比較と最適解の選び方
- 7 7. まとめ
- 8 FAQ(よくある質問)
- 8.1 Q1. setやdict.fromkeysはどちらが速いですか?
- 8.2 Q2. 元のリストの順番を保ったまま重複を削除したい場合はどうすればいいですか?
- 8.3 Q3. リスト内にさらにリストや辞書がある場合、setやdict.fromkeysを使うとエラーが出ます。どうしたら良いですか?
- 8.4 Q4. pandasで特定の列だけを基準に重複を削除したい場合は?
- 8.5 Q5. 重複要素だけをすべて削除し、1回だけ登場する値のみ残したい場合は?
- 8.6 Q6. DataFrameで重複行を「削除」ではなく「確認」したい場合は?
- 8.7 Q7. 数十万件規模のデータで重複削除をしたい場合、気をつけることは?
- 8.8 Q8. なぜ重複削除が必要なのですか?
1. はじめに
データ分析やプログラミングの現場で、「重複データの削除」は必須とも言える基本的な処理です。Pythonを使ってリストや配列、データフレームから重複要素を除去したい――そんなニーズは、初心者から上級者まで幅広い層で見られます。
たとえば、ウェブスクレイピングで大量のデータを取得した後や、CSVファイルを読み込んだとき。同じ値や行が何度も現れることは珍しくありません。こうした「重複」をそのまま放置すると、集計結果が正確に出せなくなったり、無駄な処理が発生したりと、さまざまなトラブルにつながります。
Pythonには、標準機能や外部ライブラリを使ったさまざまな重複削除の方法が用意されています。この記事では、Pythonで重複を削除するための基本的なテクニックから、応用的な使い方、注意点まで幅広く解説します。プログラム初心者の方にも分かりやすく、また実務で使う上級者にも役立つように、リスト・配列・DataFrameそれぞれのケースごとに具体例とポイントをまとめています。
「どの方法を選べばいいの?」「なぜ順序が変わるの?」といった疑問にも答えながら、実際の現場ですぐに使えるノウハウを紹介します。
Pythonで効率よく重複データを削除したい方は、ぜひ参考にしてください。
2. Pythonで重複要素を削除する基本3パターン
Pythonでリストや配列などの重複要素を削除する場合、主に以下の3つの方法がよく使われます。それぞれに特徴があるため、目的や状況に応じて使い分けることが大切です。
2.1 setによる重複削除(順序を保持しない方法)
もっともシンプルで直感的な方法は、Pythonの標準データ型である「set(セット)」を使う方法です。setは重複を許さないコレクションなので、リストをset型に変換するだけで自動的に重複要素が削除されます。
numbers = [1, 2, 2, 3, 4, 4, 5]
unique_numbers = list(set(numbers))
print(unique_numbers) # 出力例: [1, 2, 3, 4, 5]
ただし、setは要素の順序を保持しません。そのため、元のリストの順番にこだわりがある場合は別の方法が必要です。
2.2 dict.fromkeysによる順序保持型削除
Python 3.7以降では、辞書(dict)のキーの順序が保持される仕様となりました。これを利用した重複削除のテクニックが「dict.fromkeys()」です。この方法なら元のリストの順番を崩さずに、重複だけを取り除くことができます。
numbers = [1, 2, 2, 3, 4, 4, 5]
unique_numbers = list(dict.fromkeys(numbers))
print(unique_numbers) # 出力例: [1, 2, 3, 4, 5]
簡潔な一行で順序保持の重複削除ができるため、多くの場面で活用されています。
2.3 リスト内包表記+setによる順序保持と柔軟性
もう一つよく使われるのが、リスト内包表記とsetを組み合わせて順序を保持しつつ重複を除去する方法です。このやり方は、より柔軟な条件付けや複雑なデータ構造にも対応しやすい点がメリットです。
numbers = [1, 2, 2, 3, 4, 4, 5]
seen = set()
unique_numbers = [x for x in numbers if not (x in seen or seen.add(x))]
print(unique_numbers) # 出力例: [1, 2, 3, 4, 5]
この方法では、「すでに出現した要素はスキップする」という流れを明示的に記述できるため、条件付きの重複削除や、非ハッシュ可能な要素の対応も応用しやすくなります。
3. 要素がリストなど「非ハッシュable」の場合の処理
これまで紹介したsetやdictを使った重複削除は、リストやタプルなど「ハッシュ可能(hashable)」な要素に対して有効です。しかし、Pythonのリストは「非ハッシュable」なオブジェクトであるため、リストを含むリスト(二次元リストなど)や、辞書のリストなどをsetやdictのキーに直接使うことはできません。そのため、少し工夫が必要になります。
たとえば、以下のような二次元リストを考えてみましょう。
data = [[1, 2], [3, 4], [1, 2], [5, 6]]
この場合、setやdict.fromkeys()ではエラーになってしまいます。そこで、「既に現れたリストと同じものがあるかどうか」を手動でチェックしながら、重複を除去する方法が使われます。
3.1 内包表記+リストを使う方法
最も簡単なのは、「既出リストの一覧」を別途保持しながら一つずつ追加していく方法です。
data = [[1, 2], [3, 4], [1, 2], [5, 6]]
unique_data = []
for item in data:
if item not in unique_data:
unique_data.append(item)
print(unique_data) # 出力例: [[1, 2], [3, 4], [5, 6]]
このやり方なら、リスト・辞書・セットなどハッシュ不可能な要素でも順序を保ったまま重複を取り除くことができます。
3.2 より汎用的な関数化
処理を汎用的にするため、関数として定義しておくと便利です。
def remove_duplicates(seq):
result = []
for item in seq:
if item not in result:
result.append(item)
return result
data = [[1, 2], [3, 4], [1, 2], [5, 6]]
print(remove_duplicates(data)) # [[1, 2], [3, 4], [5, 6]]
3.3 性能と注意点
この方法は「順序も保てる」という利点がある一方、リストが大きい場合はitem not in result
の検索コストが高くなります。要素数が数千件程度までなら実用的ですが、数万件を超えるデータでは他の方法(たとえば要素をタプルに変換してsetで管理する等)も検討した方が良いでしょう。
4. 応用編:重複のみ抽出 or 出現回数カウント
重複削除はデータ前処理の基本ですが、実際の現場では「重複している要素だけを抽出したい」「各要素が何回出現しているかを数えたい」といった要望もよくあります。Pythonでは、これらの処理も標準ライブラリを使って簡単に実現できます。
4.1 重複している要素だけを抽出する
リストの中から「複数回現れる要素」だけを抽出したい場合、collectionsモジュールのCounter
クラスを使うと便利です。
from collections import Counter
data = [1, 2, 2, 3, 4, 4, 4, 5]
counter = Counter(data)
duplicates = [item for item, count in counter.items() if count > 1]
print(duplicates) # 出力例: [2, 4]
この方法なら、「重複がある要素」を一目で取り出すことができます。もちろん、文字列やその他のハッシュ可能なオブジェクトでも利用可能です。
4.2 各要素の出現回数をカウントする
Counter
は、各要素の出現回数も簡単に取得できます。集計や頻度分析にも使えるため、データ分析の現場で非常に重宝されています。
from collections import Counter
data = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
counter = Counter(data)
print(counter) # 出力例: Counter({'apple': 3, 'banana': 2, 'orange': 1})
Counterオブジェクトは辞書と同じように使えますので、特定の要素が何回出現したかを簡単に調べることができます。

4.3 重複を全て削除(唯一の要素だけを残す)
重複している要素をすべて除去し、「一度だけ登場した要素」だけを残す場合もCounterを活用できます。
from collections import Counter
data = [1, 2, 2, 3, 4, 4, 5]
counter = Counter(data)
unique_items = [item for item, count in counter.items() if count == 1]
print(unique_items) # 出力例: [1, 3, 5]
このように、データの用途や目的に合わせて「重複のみ」「出現回数」「唯一の要素」など、さまざまな抽出や集計が柔軟にできます。
5. Pandas DataFrameにおける重複削除
データ分析や機械学習の現場でよく利用されるのが、pandasのDataFrameです。表形式のデータを効率よく扱えるpandasには、重複データの検出や削除に特化した便利な機能が備わっています。
5.1 drop_duplicates() で重複行を削除する
pandasで最もよく使われるのが drop_duplicates()
メソッドです。これは、DataFrameやSeriesから重複した行(または列)を簡単に削除できる関数です。
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Alice', 'David'],
'age': [24, 27, 24, 32]
})
df_unique = df.drop_duplicates()
print(df_unique)
# 出力例:
# name age
# 0 Alice 24
# 1 Bob 27
# 3 David 32
この例では、完全に同じ内容の行が重複している場合、そのうち最初の行だけが残ります。
5.2 特定の列だけで重複を判断する(subset引数)
特定の列だけを基準に重複を判定したい場合は、subset
引数を使います。
df_unique_name = df.drop_duplicates(subset=['name'])
print(df_unique_name)
# 出力例:
# name age
# 0 Alice 24
# 1 Bob 27
# 3 David 32
この場合、「name」列の重複のみを判断基準としています。
5.3 重複行をマークする duplicated()
削除ではなく「どの行が重複しているか」を判定したい場合は、duplicated()
メソッドを使います。
print(df.duplicated())
# 出力例:
# 0 False
# 1 False
# 2 True
# 3 False
# dtype: bool
重複している行はTrue
、そうでない行はFalse
で示されます。これを利用して、重複行のみ抽出・削除することも可能です。
5.4 よく使うオプション(keep, inplace, ignore_index)
- keep:
'first'
(デフォルト。最初の1件だけ残す)、'last'
(最後の1件だけ残す)、False
(すべての重複を削除) - inplace:
True
にすると元のDataFrameを直接更新 - ignore_index:
True
にするとインデックスが振り直される
df.drop_duplicates(subset=['name'], keep=False, inplace=True)
この例では、「name」が重複している行をすべて削除します。
6. パフォーマンス比較と最適解の選び方
Pythonで重複削除を行う場合、選択する方法によって実行速度やメモリ効率に大きな違いが出ることがあります。ここでは、よく使われる手法のパフォーマンス傾向と、用途に応じた最適な選び方について解説します。
6.1 setとdict.fromkeysの速度比較
基本的に、set
やdict.fromkeys
を使った重複削除は非常に高速です。
- set:最もシンプルで高速。ただし、順序は保持されません。
- dict.fromkeys:順序保持が必要な場合に最適。Python 3.7以降では挿入順を維持しつつ、高速な処理が可能です。
どちらも、数万件規模のリストでもストレスなく処理できます。ただし、dict.fromkeysはキーにできない(非ハッシュ可能)要素には使えません。
6.2 リスト内包表記+setとの比較
リスト内包表記+set(seen
を使う方法)は、順序保持しつつも速度が比較的高いのが特徴です。
しかし、setやdict.fromkeysよりは若干遅くなります(要素数が増えるほど差が大きくなる傾向)。
この方法は「条件付きで重複削除したい」「複雑なデータ構造にも対応したい」といった柔軟性が求められる場合に特に有効です。
6.3 非ハッシュ可能な要素の場合
リストの中にリストや辞書などが入っている場合、item not in result
の検索コストがO(n^2)になるため、数千件を超えると処理が遅くなります。
大量データで順序保持が必要な場合は、データ構造自体を見直す(タプル化する・IDで管理する等)ことも検討しましょう。
6.4 pandasのdrop_duplicatesのパフォーマンス
pandasのdrop_duplicates
は内部で最適化されており、数十万行〜百万行規模のデータでも高速に動作します。
ただし、複雑な条件や多カラム指定が重なると、やや処理時間が伸びる場合があります。メモリ使用量にも注意が必要です。
6.5 使い分けの指針まとめ
- データ量が多く、順序にこだわらない場合:
set
が最速 - 順序も大切にしたい場合:
dict.fromkeys
またはリスト内包表記+set - 非ハッシュ可能な要素や複雑な条件がある場合:リスト内包表記+リスト、または関数化
- データ分析・大量データ・CSV等の場合:pandasの
drop_duplicates
- 出現回数や重複要素の集計も必要な場合:
collections.Counter
それぞれの方法の特徴と、自分が扱うデータの特性・用途に合わせて最適な方法を選びましょう。
7. まとめ
Pythonでの重複削除は、データ処理や分析の現場で必須のテクニックです。本記事では、リストや配列、そしてpandasのDataFrameに対する重複削除の方法を基礎から応用まで体系的に解説しました。
主なポイントを整理すると、以下の通りです。
- setを使えば、最もシンプルかつ高速に重複削除ができる。ただし順序は保持されない。
- dict.fromkeysやリスト内包表記+setなら、元の順序を保ったまま重複を除去できる。
- 非ハッシュ可能な要素(リスト・辞書など)がある場合は、
item not in result
のような内包表記+リストの手法が有効。 - collections.Counterを使うことで、「重複要素のみ抽出」や「出現回数の集計」など、より細かい集計や分析にも対応できる。
- pandasのdrop_duplicatesやduplicatedは、大規模データにも対応した強力な重複削除機能を提供し、データ分析の現場で不可欠。
また、各手法には得意・不得意や速度・メモリ効率の違いがあります。
「処理速度が重要」「順序を守りたい」「非ハッシュableなデータを扱う」など、自分の状況やデータの特性に合わせて使い分けることが、効率的で正確なデータ処理のコツです。
重複削除はシンプルなようで奥が深く、正しい手法を知っているだけでPythonでのデータ処理が格段にスムーズになります。ぜひ本記事の内容を、実際の業務や学習に役立ててみてください。
FAQ(よくある質問)
Q1. setやdict.fromkeysはどちらが速いですか?
一般的に、setを使った重複削除が最も高速です。ただし、setは要素の順序を保持しません。順序を守りたい場合はdict.fromkeysを使いましょう。Python 3.7以降のdict.fromkeysもかなり高速なので、用途によって使い分けができます。
Q2. 元のリストの順番を保ったまま重複を削除したい場合はどうすればいいですか?
dict.fromkeys、またはリスト内包表記+set(seen集合を利用する方法)が有効です。どちらも順序を維持できます。setだけを使うと順序が崩れます。
Q3. リスト内にさらにリストや辞書がある場合、setやdict.fromkeysを使うとエラーが出ます。どうしたら良いですか?
非ハッシュ可能な要素(リスト、辞書など)はsetやdictのキーにできません。その場合は、「すでに追加済みかどうか」をリストでチェックしながら手動でappendする方法(for文+if文、または関数化)が最も確実です。
Q4. pandasで特定の列だけを基準に重複を削除したい場合は?
drop_duplicatesのsubset引数を使いましょう。たとえば df.drop_duplicates(subset=['name'])
のように記述すれば、「name」列のみを基準に重複を判定できます。
Q5. 重複要素だけをすべて削除し、1回だけ登場する値のみ残したい場合は?
collections.Counterを利用し、出現回数が1回の要素だけを抽出しましょう。
from collections import Counter
data = [1, 2, 2, 3, 4, 4, 5]
counter = Counter(data)
unique_items = [item for item, count in counter.items() if count == 1]
# unique_items = [1, 3, 5]
Q6. DataFrameで重複行を「削除」ではなく「確認」したい場合は?
duplicated()メソッドを使いましょう。重複行にはTrueが、それ以外にはFalseが返ります。重複部分だけ抽出したい場合にも活用できます。
Q7. 数十万件規模のデータで重複削除をしたい場合、気をつけることは?
setやpandasのdrop_duplicatesは大量データにも強いですが、メモリ使用量や実行時間が急増する場合があります。適宜サンプリングや分割処理も検討しましょう。
Q8. なぜ重複削除が必要なのですか?
重複データをそのままにしておくと、統計分析やグラフ作成、機械学習などで誤った結果につながる可能性があります。信頼できる分析や集計のためにも、重複削除は重要な前処理です。