python清理数据
作者:互联网
流程
在进行任何清理操作之前,请先将每份数据备份,所有清理操作请在这份复件上进行,保留肮脏和/或凌乱的原始数据集以便日后查看。要在 pandas 中复制数据框,请使用copy
方法。如果原始数据框名为 df
,你可以把即将清理干净的数据集复件命名为 df_clean
。
df_clean = df.copy()
import pandas as pd
df = pd.read_csv('animals.csv')
df.head()
df_clean = df.copy()
# 使用字符串分割,删除每个动物名称前面的 'bb'
df_clean['Animal'] = df_clean['Animal'].str[2:]
# 在体重和脑重量两列,将 ! 替换为 .
df_clean['Body weight (kg)'] = df_clean['Body weight (kg)'].str.replace('!', '.')
df_clean['Brain weight (g)'] = df_clean['Brain weight (g)'].str.replace('!', '.')
df_clean.head()
# 利用 dirty animals.csv 重新加载 df_clean
df_clean = df.copy()
df_clean['Animal'] = df_clean['Animal'].str[2:]
df_clean.Animal.head()
df_clean['Body weight (kg)'] = df_clean['Body weight (kg)'].str.replace('!', '.')
df_clean['Brain weight (g)'] = df_clean['Brain weight (g)'].str.replace('!', '.')
df_clean.head()
收集
import pandas as pd
patients = pd.read_csv('patients.csv')
treatments = pd.read_csv('treatments.csv')
adverse_reactions = pd.read_csv('adverse_reactions.csv')
patients.info()
treatments.info()
adverse_reactions.info()
all_columns = pd.Series(list(patients) + list(treatments) + list(adverse_reactions))
all_columns[all_columns.duplicated()]
list(patients)
patients[patients['address'].isnull()]
patients.describe()
treatments.describe()
patients.sample(5)
patients.surname.value_counts()
patients.address.value_counts()
patients[patients.address.duplicated()]
patients.weight.sort_values()
weight_lbs = patients[patients.surname == 'Zaitseva'].weight * 2.20462
height_in = patients[patients.surname == 'Zaitseva'].height
bmi_check = 703 * weight_lbs / (height_in * height_in)
bmi_check
patients[patients.surname == 'Zaitseva'].bmi
sum(treatments.auralin.isnull())
sum(treatments.novodra.isnull())
质量
patients
表格
- 邮编是浮点,而不是字符串
- 邮编有时是四位数
- Tim Neudorf 的身高是 27 英尺,而不是 72 英尺
- 有时使用州的全称,其他用简称
- Dsvid Gustafsson
- 缺少人口统计信息 (地址列至联系方式列) (无法清理)
- 错误的数据类型 (指定性别、州、邮编和出生日期列)
- 多个手机号格式
- John Doe 的默认数据
- Jakobsen、Gersten、Taylor 多条记录
- Zaitseva 体重单位是 kgs,不是 lbs
treatments
表格
- 缺少 HbA1c 变化
- Auralin 和 Novodra 初始剂量和最终剂量中的字母 'u'
- 小写形式的姓和名
- 缺少记录 (280 而不是 350)
- 错误的数据类型 (auralin 和 novodra 列)
- HbA1c 变化不准确 (首个 4s 误写为 9s)
- auralin 和 novodra 列中空值用破折号 (-) 表示
adverse_reactions
表格
- 小写形式的姓和名
清洁度
patients
表格中的联系方式一列包括两个变量:手机号和邮箱treatments
表格两列中的三个变量 (治疗、初始剂量和最终剂量)- 不良反应应是
treatments
表格的一部分 patients
表格中的姓和名两列复制到treatments
和adverse_reactions
表格中
清理
patients_clean = patients.copy()
treatments_clean = treatments.copy()
adverse_reactions_clean = adverse_reactions.copy()
缺失数据
treatments
:缺少记录 (280 而不是 350)
定义
将 treatments_cut.csv 导入一个 DataFrame 中,并它拼接到初始的 treatments DataFrame 中。
treatments_cut = pd.read_csv('treatments_cut.csv')
treatments_clean = pd.concat([treatments_clean, treatments_cut],
ignore_index=True)
treatments_clean.head()
treatments_clean.tail()
treatments
:缺少 HbA1c 变化和 HbA1c 变化不准确 (首个 4s 误写为 9s)
定义
重新计算 hba1c_change
一列:hba1c_start
减去 hba1c_end
。
treatments_clean.hba1c_change = (treatments_clean.hba1c_start -
treatments_clean.hba1c_end)
treatments_clean.hba1c_change.head()
清洁度
patients
表格中的联系方式一列包括两个变量:手机号和邮箱
定义
使用正则表达式和 pandas 的 str.extract
方法,从 联系方式 一列提取变量手机号 和 邮箱 。完成后删除 联系方式 一列。
patients_clean['phone_number'] = patients_clean.contact.str.extract('((?:\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4})', expand=True)
patients_clean['email'] = patients_clean.contact.str.extract('([a-zA-Z][a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.][a-zA-Z]+)', expand=True)
# Note: axis=1 表明我们参考的是一列,而不是一行
patients_clean = patients_clean.drop('contact', axis=1)
# 确认联系方式一列可以运行
list(patients_clean)
patients_clean.phone_number.sample(25)
# 确认没有邮箱以整数开头 (正则表达式不能匹配整数)
patients_clean.email.sort_values().head()
treatments
表格两列中的三个变量 (治疗、初始剂量和最终剂量)
定义
在 auralin 和 novodra 两列中加入 治疗 和 剂量 列 (这时剂量仍然包含初始剂量和最终剂量)。然后使用破折号 ' - ' 把剂量列切分,得到 初始剂量 和 最终剂量 两列。删除中间使用的 剂量 一列。
treatments_clean = pd.melt(treatments_clean, id_vars=['given_name', 'surname', 'hba1c_start', 'hba1c_end', 'hba1c_change'],
var_name='treatment', value_name='dose')
treatments_clean = treatments_clean[treatments_clean.dose != "-"]
treatments_clean['dose_start'], treatments_clean['dose_end'] = treatments_clean['dose'].str.split(' - ', 1).str
treatments_clean = treatments_clean.drop('dose', axis=1)
treatments_clean.head()
不良反应应是 treatments
表格的一部分
定义
将 不良反应 一列合并到 treatments
表格中,按照 名* 和 *姓进行合并。
treatments_clean = pd.merge(treatments_clean, adverse_reactions_clean,
on=['given_name', 'surname'], how='left')
treatments_clean
patients
表格中的姓和名两列复制到 treatments
和 adverse_reactions
表格中,以及小写形式的姓和名
定义
我们不再需要不良反应表格,所以忽略这部分内容。在 patients
表格中,提取病人编号和姓名,然后把这些名字改为小写形式,加入到 treatments
表格中。然后删除治疗表格中的姓和名两列 (这样小写形式不再是问题了)。
id_names = patients_clean[['patient_id', 'given_name', 'surname']]
id_names.given_name = id_names.given_name.str.lower()
id_names.surname = id_names.surname.str.lower()
treatments_clean = pd.merge(treatments_clean, id_names, on=['given_name', 'surname'])
treatments_clean = treatments_clean.drop(['given_name', 'surname'], axis=1)
# 确认进行了正确融合
treatments_clean
# Patient ID should be the only duplicate column
all_columns = pd.Series(list(patients_clean) + list(treatments_clean))
all_columns[all_columns.duplicated()]
质量
邮编是浮点,而不是字符串,有时是四位数
定义
Convert the zip code column's data type from a float to a string 使用 astype
把邮件一列的数据类型从浮点转换为字符串,使用字符串分割删除 '.0'。在四位数邮编前面加上 0。
patients_clean.zip_code = patients_clean.zip_code.astype(str).str[:-2].str.pad(5, fillchar='0')
# 对于上面代码转化后的'0000n'非数字条目,进行再次转化
patients_clean.zip_code = patients_clean.zip_code.replace('0000n', np.nan)
patients_clean.zip_code.head()
Tim Neudorf 的身高是 27 英尺,而不是 72 英尺
定义
在 patients
表格中身高为 27 英尺 (仅有一个) 的一行身高,替换为72英尺。
patients_clean.height = patients_clean.height.replace(27, 72)
# 应为空
patients_clean[patients_clean.height == 27]
# 确认完成替换
patients_clean[patients_clean.surname == 'Neudorf']
有时使用州的全称,其他用简称
定义
使用函数,将 California (加利福尼亚)、New York (纽约)、Illinois (伊利诺伊)、Florida (佛罗里达) 和 Nebrask (内布拉斯加) 等州的全称转变为简称。
# 从州的全称映射到简称
state_abbrev = {'California': 'CA',
'New York': 'NY',
'Illinois': 'IL',
'Florida': 'FL',
'Nebraska': 'NE'}
# 使用的函数
def abbreviate_state(patient):
if patient['state'] in state_abbrev.keys():
abbrev = state_abbrev[patient['state']]
return abbrev
else:
return patient['state']
patients_clean['state'] = patients_clean.apply(abbreviate_state, axis=1)
patients_clean.state.value_counts()
Dsvid Gustafsson
Define
在 patients
表格中含有名 'Dsvid' 的一行里替换为'David'。
patients_clean.given_name = patients_clean.given_name.replace('Dsvid', 'David')
patients_clean[patients_clean.surname == 'Gustafsson']
错误的数据类型 (指定性别、州、邮编和出生日期列) 和错误的数据类型 (auralin 和 novodra 列),以及 Auralin 和 Novodra 初始剂量和最终剂量中的字母 'u'
Define
将指定性别和州转化为分类数据类型。上面已经解决了邮编的数据类型。把出生日期转化为 datetime 数据类型。在初始剂量和最终剂量中添加字母 'u',并把这些列转化为整数数据类型。
# 转为分类数据类型
patients_clean.assigned_sex = patients_clean.assigned_sex.astype('category')
patients_clean.state = patients_clean.state.astype('category')
# 转为 datetime 类型
patients_clean.birthdate = pd.to_datetime(patients_clean.birthdate)
# 添加 u 并转为整数类型
treatments_clean.dose_start = treatments_clean.dose_start.str.strip('u').astype(int)
treatments_clean.dose_end = treatments_clean.dose_end.str.strip('u').astype(int)
patients_clean.info()
treatments_clean.info()
多个手机号格式
定义
增加所有的 " "、 "-"、"(", ")" 和 "+",存储所有没有格式的数字。如果手机号只有 10 位数,在手机号前添加 1 (我们需要国家编号)。
patients_clean.phone_number = patients_clean.phone_number.str.replace(r'\D+', '').str.pad(11, fillchar='1')
patients_clean.phone_number.head()
John Doe 的默认数据
定义
从 patients
表格中删除不可恢复的 John Doe 记录。
patients_clean = patients_clean[patients_clean.surname != 'Doe']
# 应该没有 Doe 记录
patients_clean.surname.value_counts()
# 应该没有 123 Main Street 记录
patients_clean.address.value_counts()
Jakobsen、Gersten、Taylor 多条记录
定义
从 patients
表格中删除 Jake Jakobsen、Pat Gersten 和 Sandy Taylor。这些是昵称,不应该出现在 treatments
表格中 (删除错误名字可以保证 patients
和 treatments
表格的一致性问题)。这些是复制后第二次出现。这些是唯一出现的非空值复制地址。
# 波浪符号表示否: http://pandas.pydata.org/pandas-docs/stable/indexing.html#boolean-indexing
patients_clean = patients_clean[~((patients_clean.address.duplicated()) & patients_clean.address.notnull())]
patients_clean[patients_clean.surname == 'Jakobsen']
patients_clean[patients_clean.surname == 'Gersten']
patients_clean[patients_clean.surname == 'Taylor']
Zaitseva 体重单位是 kgs,不是 lbs
定义
使用 高级索引 把姓是 Zaitseva 的行隔离出来,并把体重单元格中的 kg 改为 lbs。
weight_kg = patients_clean.weight.sort_values()[210]
mask = patients_clean.surname == 'Zaitseva'
column_name = 'weight'
patients_clean.loc[mask, column_name] = weight_kg * 2.20462
# 48.8 不应该是最低的
patients_clean.weight.sort_values()
清理数据有两种:
- 人工清理 (不推荐,除非问题只会发生一次)
- 程序清理
数据程序清理流程:
- 确定方案:将评估结果转化为具体的清理任务。这些确定下来的方案可作为指引列表,供他人 (或未来的你) 观察你的工作并重现操作。
- 编写代码:将定下来的方案转化为代码并运行。
- 检验效果:检验你的数据集,你可以直接用肉眼观察或使用代码来检验,确保清理操作起到了应有的效果。
在进行清理之前,请千万对原始数据进行备份!
标签:surname,str,python,清理,treatments,df,patients,clean,数据 来源: https://blog.csdn.net/m493096871/article/details/89476515