目次
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]
這種方法可以明確描述「已經出現的元素則跳過」的流程,因此容易應用於有條件的重複刪除,或是處理無法雜湊的元素。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 的速度比較
基本上,使用set
或 dict.fromkeys
進行重複刪除的速度非常快。- set:最簡單且高速。不過,不會保持順序。
- dict.fromkeys:需要保持順序時最適。Python 3.7 以降會維持插入順序,同時進行高速處理。
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,提供了對應大規模資料的強力重複刪除功能,在資料分析現場中不可或缺。
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]