本文目录导读:

我来分享几个Python数据库去重的实用案例,涵盖不同场景和实现方式。
基础SQL去重 - SQLite案例
import sqlite3
# 创建测试数据
conn = sqlite3.connect('test.db')
cursor = conn.cursor()
# 创建表并插入重复数据
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT,
age INTEGER
)
''')
# 插入重复数据
test_data = [
('张三', 'zhangsan@email.com', 25),
('李四', 'lisi@email.com', 30),
('张三', 'zhangsan@email.com', 25), # 重复
('王五', 'wangwu@email.com', 28),
('张三', 'zhangsan@email.com', 25), # 重复
]
cursor.executemany('INSERT INTO users (name, email, age) VALUES (?, ?, ?)', test_data)
conn.commit()
# 方法1:使用DISTINCT去重
print("=== DISTINCT去重 ===")
cursor.execute('SELECT DISTINCT name, email, age FROM users')
for row in cursor.fetchall():
print(f"姓名: {row[0]}, 邮箱: {row[1]}, 年龄: {row[2]}")
# 方法2:使用GROUP BY去重
print("\n=== GROUP BY去重 ===")
cursor.execute('''
SELECT name, email, age, COUNT(*) as count
FROM users
GROUP BY name, email, age
HAVING COUNT(*) > 0
''')
for row in cursor.fetchall():
print(f"姓名: {row[0]}, 邮箱: {row[1]}, 年龄: {row[2]}, 重复次数: {row[3]}")
conn.close()
使用Pandas高级去重
import pandas as pd
from datetime import datetime
# 创建包含重复数据的DataFrame
data = {
'订单号': ['A001', 'A002', 'A001', 'A003', 'A002', 'A004'],
'商品': ['苹果', '香蕉', '苹果', '橘子', '香蕉', '葡萄'],
'数量': [5, 3, 5, 8, 4, 6],
'日期': ['2024-01-01', '2024-01-02', '2024-01-01', '2024-01-03', '2024-01-02', '2024-01-04']
}
df = pd.DataFrame(data)
print("=== 原始数据 ===")
print(df)
# 方法1:完全重复行去重
df_unique = df.drop_duplicates()
print("\n=== 完全去重 ===")
print(df_unique)
# 方法2:指定列去重(保留第一次出现的)
df_partial = df.drop_duplicates(subset=['订单号'], keep='first')
print("\n=== 按订单号去重(保留第一个)===")
print(df_partial)
# 方法3:指定列去重(保留最后一次出现的)
df_last = df.drop_duplicates(subset=['订单号'], keep='last')
print("\n=== 按订单号去重(保留最后一个)===")
print(df_last)
# 方法4:基于条件的去重(保留数量最大的)
df_max = df.loc[df.groupby('订单号')['数量'].idxmax()]
print("\n=== 按订单号去重(保留数量最大的)===")
print(df_max)
复杂场景:多条件去重
import pandas as pd
from datetime import datetime, timedelta
import random
# 模拟销售数据
def generate_sales_data():
products = ['手机', '电脑', '平板', '耳机', '手表']
cities = ['北京', '上海', '广州', '深圳', '杭州']
data = []
# 创建一些重复数据
repeat_data = [
('手机', '北京', 5000, '2024-01-01'),
('手机', '北京', 5000, '2024-01-01'), # 重复
('电脑', '上海', 8000, '2024-01-02'),
('电脑', '上海', 8000, '2024-01-02'), # 重复
('平板', '广州', 3000, '2024-01-03'),
]
for product, city, price, date in repeat_data:
data.append({'产品': product, '城市': city, '价格': price, '日期': date})
# 添加一些不重复的数据
for i in range(10):
data.append({
'产品': random.choice(products),
'城市': random.choice(cities),
'价格': random.randint(1000, 10000),
'日期': f'2024-01-{(i+10):02d}'
})
return pd.DataFrame(data)
df = generate_sales_data()
print("=== 原始销售数据 ===")
print(df)
# 多条件去重:产品和城市组合唯一
df_multi_unique = df.drop_duplicates(subset=['产品', '城市'], keep='first')
print("\n=== 产品和城市组合去重 ===")
print(df_multi_unique)
# 按日期范围去重(最近一周的数据去重)
df['日期'] = pd.to_datetime(df['日期'])
last_week = df[df['日期'] >= (df['日期'].max() - timedelta(days=7))]
print("\n=== 最近一周数据去重 ===")
print(last_week.drop_duplicates(subset=['产品', '城市']))
实时数据去重(流式处理)
from collections import defaultdict
import time
import hashlib
class DeduplicationHandler:
"""实时数据去重处理器"""
def __init__(self, window_size=1000):
self.window_size = window_size
self.data_window = []
self.hash_set = set()
def _create_hash(self, data):
"""创建数据指纹"""
# 将数据转换为字符串并生成哈希
data_str = str(sorted(data.items()))
return hashlib.md5(data_str.encode()).hexdigest()
def process_data(self, data):
"""处理新数据,返回False表示重复"""
data_hash = self._create_hash(data)
if data_hash in self.hash_set:
return False # 重复数据
# 添加到窗口
self.data_window.append((data_hash, data))
self.hash_set.add(data_hash)
# 维护窗口大小
if len(self.data_window) > self.window_size:
old_hash, old_data = self.data_window.pop(0)
self.hash_set.remove(old_hash)
return True # 新数据
def get_unique_count(self):
return len(self.data_window)
# 使用示例
def simulate_realtime_data():
dedup = DeduplicationHandler(window_size=5)
test_data = [
{'sensor': 'A', 'value': 25.5, 'time': '10:00:01'},
{'sensor': 'B', 'value': 30.0, 'time': '10:00:02'},
{'sensor': 'A', 'value': 25.5, 'time': '10:00:01'}, # 重复
{'sensor': 'C', 'value': 28.0, 'time': '10:00:03'},
{'sensor': 'A', 'value': 25.5, 'time': '10:00:01'}, # 重复
]
print("=== 实时数据去重测试 ===")
for i, data in enumerate(test_data):
result = dedup.process_data(data)
status = "✓ 新数据" if result else "✗ 重复数据"
print(f"数据{i+1}: {data} -> {status}")
print(f"\n去重后唯一数据数: {dedup.get_unique_count()}")
simulate_realtime_data()
大数据量去重优化
import numpy as np
import pandas as pd
from concurrent.futures import ProcessPoolExecutor
import time
def optimized_dedup_large_dataset():
"""大数据量去重优化示例"""
# 生成100万条数据
np.random.seed(42)
print("生成100万条测试数据...")
n_rows = 1000000
df = pd.DataFrame({
'id': np.random.randint(0, 500000, n_rows),
'category': np.random.choice(['A', 'B', 'C', 'D'], n_rows),
'value': np.random.randn(n_rows),
'timestamp': pd.date_range('2024-01-01', periods=n_rows, freq='1min')
})
print(f"原始数据大小: {df.shape}")
# 方法1:使用索引去重(最快)
start_time = time.time()
df_index_dedup = df.set_index('id').index.unique()
method1_time = time.time() - start_time
print(f"\n方法1(索引去重): {len(df_index_dedup)} 条数据, 耗时: {method1_time:.3f}秒")
# 方法2:使用groupby去重
start_time = time.time()
df_groupby_dedup = df.drop_duplicates(subset=['id', 'category'])
method2_time = time.time() - start_time
print(f"方法2(groupby去重): {len(df_groupby_dedup)} 条数据, 耗时: {method2_time:.3f}秒")
# 方法3:使用哈希去重(适合大集合)
start_time = time.time()
# 创建哈希集合
hash_set = set()
for idx, row in df.iterrows():
hash_val = hash((row['id'], row['category']))
hash_set.add(hash_val)
method3_time = time.time() - start_time
print(f"方法3(哈希去重): {len(hash_set)} 个哈希值, 耗时: {method3_time:.3f}秒")
# 注意:在大数据量时,建议使用前两种方法
# optimized_dedup_large_dataset()
print("大数据量去重示例已准备,取消注释运行")
实际应用:电商订单去重
import pandas as pd
from datetime import datetime, timedelta
import uuid
class OrderDeduplication:
"""电商订单去重系统"""
def __init__(self):
self.processed_orders = set()
self.duplicate_log = []
def process_orders(self, orders_df):
"""
处理订单去重
去重规则:
1. 同一用户同一商品在24小时内下多次订单视为重复
2. 相同的收货地址和联系电话视为重复
"""
results = []
for idx, order in orders_df.iterrows():
order_key = self._create_order_key(order)
if self._is_unique(order, order_key):
results.append(order)
self.processed_orders.add(order_key)
else:
self.duplicate_log.append({
'order_id': order['order_id'],
'reason': '重复订单',
'timestamp': datetime.now()
})
return pd.DataFrame(results)
def _create_order_key(self, order):
"""创建订单唯一标识"""
# 组合用户ID、商品ID、收货地址和联系电话
key_parts = [
str(order.get('user_id', '')),
str(order.get('product_id', '')),
str(order.get('address', '')),
str(order.get('phone', ''))
]
return '_'.join(key_parts)
def _is_unique(self, order, order_key):
"""检查订单是否唯一"""
if order_key in self.processed_orders:
return False
return True
# 模拟订单数据
def simulate_order_dedup():
dedup = OrderDeduplication()
# 创建测试订单数据
orders_data = {
'order_id': [str(uuid.uuid4()) for _ in range(10)],
'user_id': [1001, 1002, 1001, 1003, 1002, 1001, 1004, 1005, 1001, 1006],
'product_id': ['P001', 'P002', 'P001', 'P003', 'P002', 'P004', 'P005', 'P006', 'P001', 'P007'],
'address': ['北京路1号', '上海路2号', '北京路1号', '广州路3号',
'深圳路4号', '北京路1号', '杭州路5号', '成都路6号',
'北京路1号', '武汉路7号'],
'phone': ['13800138001', '13800138002', '13800138001', '13800138003',
'13800138002', '13800138001', '13800138004', '13800138005',
'13800138001', '13800138006'],
'amount': [100, 200, 100, 300, 200, 150, 400, 500, 100, 600]
}
orders_df = pd.DataFrame(orders_data)
print("=== 原始订单数据 ===")
print(orders_df[['order_id', 'user_id', 'product_id', 'address', 'amount']])
# 执行去重
unique_orders = dedup.process_orders(orders_df)
print(f"\n=== 去重后的订单 ({len(unique_orders)} 条) ===")
print(unique_orders[['user_id', 'product_id', 'address', 'amount']])
print(f"\n被标记为重复的订单数: {len(dedup.duplicate_log)}")
for dup in dedup.duplicate_log:
print(f"订单 {dup['order_id']}: {dup['reason']}")
simulate_order_dedup()
总结与建议
选择合适的去重方法
- 小数据集(<1万条):使用
drop_duplicates()或SQL的DISTINCT - 中等数据集(1-100万条):使用Pandas的groupby或索引去重
- 大数据集(>100万条):考虑分布式处理或数据库层面的去重
性能优化技巧
# 1. 使用索引加速
df.set_index('id', inplace=True)
df = df[~df.index.duplicated(keep='first')]
# 2. 使用内存映射(大文件)
df = pd.read_csv('large_file.csv', usecols=['col1', 'col2'], dtype={'col1': 'category'})
# 3. 分批处理
def batch_dedup(df, batch_size=10000):
results = []
for i in range(0, len(df), batch_size):
batch = df.iloc[i:i+batch_size]
deduped = batch.drop_duplicates(subset=['key'])
results.append(deduped)
return pd.concat(results).drop_duplicates(subset=['key'])
# 4. 使用bloom filter(适合大规模去重)
from pybloom_live import BloomFilter
bloom = BloomFilter(capacity=1000000, error_rate=0.001)
这些案例覆盖了从简单到复杂的各种去重场景,你可以根据实际需求选择合适的方法。去重策略的选择应该基于数据量、重复率、业务规则和性能要求来综合考虑。