Python 移除重複全手法|清單與 DataFrame 高效批次處理指南

目次

1. 引言

資料分析或程式設計的實務現場中,「重複資料的刪除」可說是不可或缺的基本處理。使用 Python 從清單、陣列、資料框架中移除重複元素――這樣的 nhu cầu,從初學者到專家都有廣泛層級。 例如,在網路爬蟲取得大量資料之後,或是讀取 CSV 檔案時。相同的數值或列出現多次的情況並不罕見。將這樣的「重複」直接放置不管,就會導致彙總結果無法正確輸出,或是產生無謂的處理等,引發各種問題。 Python 準備了使用標準功能或外部程式庫的各種重複刪除方法。本文將從 Python 刪除重複的基本技巧,到進階用法、注意事項等,廣泛說明。為了讓程式初學者也能輕鬆理解,並對實務使用的專家有幫助,我們針對清單・陣列・DataFrame 各個案例,彙整具體範例與要點。 針對「該選哪種方法?」「為什麼順序會改變?」等疑問,也會一一解答,介紹可在實際現場立即應用的 know-how。 想要在 Python 中有效率地刪除重複資料的人,請務必參考。

2. Python 中刪除重複元素的基本三種方法

在 Python 中刪除列表或陣列等重複元素時,主要使用以下三種方法。每種方法都有其特點,因此根據目的或情況來選擇使用非常重要。

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]
這種方法可以明確描述「已經出現的元素則跳過」的流程,因此容易應用於有條件的重複刪除,或是處理無法雜湊的元素。
RUNTEQ(ランテック)|超実戦型エンジニア育成スクール

3. 元素為列表等「不可雜湊化」的處理

到目前為止介紹的利用 set 或 dict 進行重複刪除的方法,對列表或元組等「可雜湊(hashable)」的元素有效。然而,Python 的列表是「不可雜湊化」的物件,因此無法直接將包含列表的列表(二維列表等)或字典的列表等作為 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'(預設。只保留第一筆)、'last'(只保留最後一筆)、False(刪除所有重複)
  • inplace:設為 True 時,會直接更新原始 DataFrame
  • ignore_index:設為 True 時,會重新設定索引
df.drop_duplicates(subset=['name'], keep=False, inplace=True)
在這個範例中,會刪除所有「name」重複的行。

6. 效能比較與最佳解的選擇方式

在 Python 中進行重複刪除時,根據選擇的方法,執行速度或記憶體效率會有很大的差異。在這裡,我們將說明常用方法的效能趨勢,以及根據用途選擇的最佳方式。

6.1 set 與 dict.fromkeys 的速度比較

基本上,使用 setdict.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,提供了對應大規模資料的強力重複刪除功能,在資料分析現場中不可或缺。
此外,各種手法各有擅長與不擅長之處,以及速度・記憶體效率的差異。 「處理速度很重要」「想保留順序」「要處理不可雜湊的資料」等,根據自己的情況或資料特性來靈活運用,就是高效且精確的資料處理訣竅。 重複刪除看似簡單,卻深奧難測,只要知道正確的手法,就能讓 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. 如果想刪除所有重複元素,只保留只出現一次的值?

使用collections.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]
 # unique_items = [1, 3, 5]

Q6. 在DataFrame中,如果想「確認」而非「刪除」重複列?

使用duplicated()方法。重複列會回傳True,其他則回傳False。如果想抽出重複部分,也能活用此方法。

Q7. 如果是數十萬筆規模的資料想刪除重複,需要注意什麼?

set或pandas的drop_duplicates對大量資料也很強大,但記憶體使用量或執行時間可能急劇增加。適時考慮抽樣或分割處理。

Q8. 為什麼需要刪除重複?

如果保留重複資料,可能導致統計分析、圖表製作或機器學習等產生錯誤結果。為了可靠的分析與彙總,重複刪除是重要的前處理步驟。
年収訴求