
你有没有过这样的经历?
辛辛苦苦跑了一天代码,结果因为数据质量太差,得出了一堆错误结论。说实话,我之前也踩过不少坑。
直到我系统掌握了数据清洗技巧,才发现原来可以这么高效。
今天我整理了25个实用的Python数据清洗技巧,从缺失值处理到数据转换,从文本清洗到异常值检测,帮你一次搞定所有数据质量问题。
记住一句话:垃圾进,垃圾出。数据清洗不是浪费时间,而是在为你的分析保驾护航。
第一步先看看数据里有多少缺失值,做到心中有数。
import pandas as pdimport numpy as npdata = {'A': [1, 2, np.nan, 4], 'B': ['x', np.nan, 'z', 'w'], 'C': [5, 6, 7, 8]}df = pd.DataFrame(data)# 检测每列的缺失值数量missing_values = df.isnull().sum()print("缺失值统计:\n", missing_values)缺失值太多的时候,直接删除可能是最快的方法。
# 删除包含缺失值的行df_drop_rows = df.dropna()print("删除含缺失值的行:\n", df_drop_rows)# 删除包含缺失值的列df_drop_cols = df.dropna(axis=1)print("删除含缺失值的列:\n", df_drop_cols)不想删除的话,就用合理的方式填充。比如用平均值、中位数,或者前一个有效值。
# 用列平均值填充数值型缺失值df_fill_mean = df.fillna(df.mean())print("用平均值填充:\n", df_fill_mean)# 用前一个有效值填充(前向填充)df_fill_forward = df.fillna(method='ffill')print("前向填充:\n", df_fill_forward)重复数据会干扰分析结果,要及时清理。
data = {'name': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'], 'age': [25, 30, 25, 35, 30]}df = pd.DataFrame(data)# 去除完全重复的行df_no_duplicates = df.drop_duplicates()print("去重后的数据:\n", df_no_duplicates)有时候只想根据某一列去重,保留其他信息。
# 基于name列去重,保留第一次出现的记录df_no_duplicates = df.drop_duplicates(subset=['name'])print("基于name列去重:\n", df_no_duplicates)字符串里的空格、大小写问题,统一清洗一下。
text_data = {'text': [' Python ', 'JAVA ', ' C++ ', 'R ']}df_text = pd.DataFrame(text_data)# 去除空格并转为小写df_text['cleaned'] = df_text['text'].str.strip().str.lower()print("清洗后的文本:\n", df_text)移除文本中的数字和特殊字符,只保留想要的。
# 移除文本中的数字和特殊字符df_text['regex_cleaned'] = df_text['text'].str.replace(r'[^a-zA-Z\s]', '', regex=True)print("正则清洗后的文本:\n", df_text)类型不对会出大问题,确保每列都是正确的数据类型。
mixed_data = {'numbers': ['1', '2', '3', '4'], 'booleans': ['True', 'False', 'True', 'False']}df_mixed = pd.DataFrame(mixed_data)# 转换数据类型df_mixed['numbers'] = df_mixed['numbers'].astype(int)df_mixed['booleans'] = df_mixed['booleans'].astype(bool)print("转换后的数据类型:\n", df_mixed.dtypes)日期格式五花八门,统一转换成标准格式很重要。
date_data = {'dates': ['2023-01-01', '01/02/2023', 'March 3, 2023', '04-04-2023']}df_dates = pd.DataFrame(date_data)# 统一日期格式df_dates['formatted'] = pd.to_datetime(df_dates['dates'], errors='coerce')print("标准化的日期:\n", df_dates)异常值会拉偏整体趋势,用Z-score检测一下。
from scipy import statsdata = {'values': [10, 12, 11, 15, 10, 100, 9, 12, 11, 10]}df_outliers = pd.DataFrame(data)# 使用Z-score检测离群值z_scores = np.abs(stats.zscore(df_outliers['values']))df_outliers['is_outlier'] = z_scores > 2print("离群值检测结果:\n", df_outliers)把连续数据分成几个区间,方便分析和展示。
ages = [22, 25, 30, 35, 40, 45, 50, 55, 60, 65]df_ages = pd.DataFrame({'age': ages})# 将年龄分箱bins = [20, 30, 40, 50, 60, 70]labels = ['20s', '30s', '40s', '50s', '60s']df_ages['age_group'] = pd.cut(df_ages['age'], bins=bins, labels=labels)print("年龄分箱结果:\n", df_ages)不同量纲的数据放在一起分析,需要先标准化。
from sklearn.preprocessing import StandardScalerdata = {'feature1': [100, 200, 300, 400, 500], 'feature2': [0.1, 0.2, 0.3, 0.4, 0.5]}df_scale = pd.DataFrame(data)# 标准化数据scaler = StandardScaler()scaled_data = scaler.fit_transform(df_scale)df_scaled = pd.DataFrame(scaled_data, columns=df_scale.columns)print("标准化后的数据:\n", df_scaled)分类变量不能直接参与计算,要转换成数值。
categories = ['red', 'blue', 'green', 'blue', 'red', 'green']df_cat = pd.DataFrame({'color': categories})# 独热编码df_encoded = pd.get_dummies(df_cat, columns=['color'])print("独热编码结果:\n", df_encoded)类别不多的时候,标签编码比独热编码更节省空间。
from sklearn.preprocessing import LabelEncoderle = LabelEncoder()df_cat['color_label'] = le.fit_transform(df_cat['color'])print("标签编码结果:\n", df_cat)数据分散在不同表里,需要合并到一起。
df1 = pd.DataFrame({'key': ['A', 'B', 'C'], 'value1': [1, 2, 3]})df2 = pd.DataFrame({'key': ['B', 'C', 'D'], 'value2': [4, 5, 6]})# 内连接df_inner = pd.merge(df1, df2, on='key', how='inner')print("内连接结果:\n", df_inner)# 左连接df_left = pd.merge(df1, df2, on='key', how='left')print("左连接结果:\n", df_left)快速汇总数据,按不同维度聚合统计。
data = { 'city': ['北京', '上海', '北京', '上海', '北京'], 'category': ['A', 'A', 'B', 'B', 'A'], 'value': [100, 200, 150, 250, 120]}df = pd.DataFrame(data)pivot = pd.pivot_table(df, values='value', index='city', columns='category', aggfunc='sum')print("透视表结果:\n", pivot)从文本中提取特定模式的内容。
data = {'text': ['用户ID:12345', '订单号:67890', '编号:11111']}df = pd.DataFrame(data)# 提取数字df['numbers'] = df['text'].str.extract(r':(\d+)')print("提取结果:\n", df)时间序列数据经常需要按不同时间粒度聚合。
date_rng = pd.date_range(start='2023-01-01', end='2023-01-10', freq='D')data = {'date': date_rng, 'value': range(10)}df = pd.DataFrame(data).set_index('date')# 按3天重采样并求和resampled = df.resample('3D').sum()print("重采样结果:\n", resampled)JSON数据嵌套太深,需要展平成表格。
import jsonfrom pandas import json_normalizejson_data = '''{ "employees": [ { "name": "John", "age": 30, "address": { "city": "New York", "zip": "10001" } } ]}'''data = json.loads(json_data)df = json_normalize(data['employees'])print("展平后的数据:\n", df)确保数据符合业务规则,避免后续分析出错。
# 自定义数据验证def validate_data(df): errors = [] # 年龄必须在18-100之间 if 'age' in df.columns: invalid_age = df[(df['age'] < 18) | (df['age'] > 100)] if not invalid_age.empty: errors.append(f"年龄异常: {len(invalid_age)}条") # 邮箱必须包含@ if 'email' in df.columns: invalid_email = df[~df['email'].str.contains('@', na=False)] if not invalid_email.empty: errors.append(f"邮箱异常: {len(invalid_email)}条") return errorsdata = {'age': [25, 30, 17], 'email': ['a@b.com', 'c@d.com', 'invalid']}df = pd.DataFrame(data)errors = validate_data(df)print("验证结果:", errors)有离群值时,中位数比平均值更稳健。
data = {'A': [1, 2, None, 4, 100]}df = pd.DataFrame(data)# 用中位数填充df_filled = df.fillna(df.median())print("中位数填充结果:\n", df_filled)根据条件批量替换数据,比循环快得多。
data = {'age': [15, 20, 25, 30, 35]}df = pd.DataFrame(data)# 年龄小于18的替换为18df['age'] = df['age'].where(df['age'] >= 18, 18)print("条件替换结果:\n", df)时间序列数据常用滚动统计来平滑波动。
data = {'date': pd.date_range('2023-01-01', periods=10), 'value': [10, 12, 11, 15, 10, 13, 14, 12, 16, 15]}df = pd.DataFrame(data).set_index('date')# 3天移动平均df['rolling_mean'] = df['value'].rolling(window=3).mean()print("滚动窗口结果:\n", df)复杂筛选用query方法,代码更清晰。
data = { 'city': ['北京', '上海', '广州', '北京', '上海'], 'sales': [100, 200, 150, 120, 180], 'category': ['A', 'B', 'A', 'B', 'A']}df = pd.DataFrame(data)# 多条件筛选result = df.query("city == '北京' and sales > 110")print("筛选结果:\n", result)重复数据中保留最后一条,通常是最新的信息。
data = { 'id': [1, 2, 1, 3, 2], 'value': [100, 200, 150, 300, 250], 'date': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05']}df = pd.DataFrame(data)# 按id去重,保留最新日期的记录df['date'] = pd.to_datetime(df['date'])df_latest = df.sort_values('date').drop_duplicates('id', keep='last')print("去重并保留最新:\n", df_latest)这25个技巧覆盖了数据清洗中最常见的场景。记住,数据清洗不是一次性工作,而是一个持续的过程。
实战建议:
✓ 先做数据探索,了解数据全貌
✓ 从简单处理开始,逐步深入
✓ 保留原始数据,方便回滚
✓ 记录清洗过程,方便复用
数据质量决定分析的上限。花在数据清洗上的时间,永远不会是浪费。
往期Python阅读>>
Python 自动化做数据可视化10个示例(含代码),强烈推荐
你平时用哪些数据清洗技巧?有没有踩过什么坑?评论区聊聊吧~
如果这篇文章对你有帮助,点个在看让更多人看到吧 👇
想高效学习Python?下面三本精选好书满足你的不同需求!
《流畅的Python(第2版)》——Python进阶必读!深入讲解高级特性与最佳实践,适合想精进的开发者。
《Python从新手到高手》:初学者首选,系统学习全栈技能。
《Python数据分析:从零基础入门到案例实战》——数据科学利器!手把手教你用Python处理数据,实战案例学完就能用。
三本书均支持先用后付、运费险和7天无理由退货,放心购买!点击“购买”按钮,立即开启你的Python学习之旅吧!
https://ima.qq.com/wiki/?shareId=f2628818f0874da17b71ffa0e5e8408114e7dbad46f1745bbd1cc1365277631c
