最近看了一个up主讲基本数据清洗操作,觉得非常好,链接如下:
评论区也有原数据集和相关代码的链接(不是广告),下面就浅浅记一下自己的学习笔记。除此之外,up主的缺失值处理是直接用均值进行替代,个人觉得不是很严谨,所以替换成了随机森林算法填补缺失值。
需要注意的是,正常的顺序应该是先进行缺失值处理,再进行文本提取、时间处理等操作,但是因为我用随机森林的时候需要用文本提取来创造新变量,所以把两者顺序调转了一下。
1. 读取数据
2. 数据探索与描述
3. 数据简单处理
4. 文本字符串/时间格式序列处理
5. 缺失值/异常值处理
6. 总结(思维导图)
import pandas as pd
df = pd.read_csv(".\qunar_freetrip.csv",index_col = 0)
df.head()
df.info()
df.describe()
df.shape
# 通过该命令发现列名有空格
col = df.columns.values
#进行清洗
df.columns = [x.strip() for x in col]
df.columns
# 重复值
df.duplicated() #返回布尔型数据,告诉重复值的位置
df[df.duplicated()] #返回重复数值
df.duplicated().sum() #返回重复值数量
df.drop_duplicates(inplace = True) # 删除重复值,inplace=True表示在原数据集上进行操作
# 需要注意的是去重之后需要索引重置
df.reset_index()
# 正则提取酒店评分等信息
# ''里面是规则;()里面是提取内容
import re
df['酒店评分'] = df['酒店'].str.extract('(\d\.\d)分/5分',expand = False)
df['酒店等级'] = df['酒店'].str.extract(' (.+) ', expand = False)
df['time_start'] = [x.split('-')[0].strip() for x in df['去程时间']]
df['time_end'] = [x.split('-')[1].strip() for x in df['去程时间']]
df['天数'] = df['房间'].str.extract('\d+间(\d+)晚', expand = False)
df['航空公司'] = [re.findall(r'[\u4e00-\u9fff]+',x)[0] for x in df['去程航司']]
# 时间格式处理
from datetime import datetime as dt
df['start'] = [dt.strptime(x,'%H:%M') for x in df['time_start']]
df['end'] = [dt.strptime(y,'%H:%M') for y in df['time_end']]
df['minute'] = [round(x.seconds/60,0) for x in (df['end'] - df['start'])]
df = df.drop(df[['end','start']],axis = 1)
#(1)异常值
## (a)异常值检测
### motivation: 对缺失值进行处理的时候需要考虑去掉异常值
df.describe().T
### 发现最大值比较离谱,现在对异常值进行定义,在三倍标准差之外的是异常值
sta = (df['价格']-df['价格'].mean())/df['价格'].std()
### 找出价格异常值
df[sta.abs()>3] #此时需要和业务进行了解,这个异常值的原因,是输入错误还是
### 找出节省异常值
df[df['价格']3]]).index #获取异常值的index
df.drop(deindex, inplace = True) #
df = df.reset_index()
# 缺失值
## (a)缺失值检测
### 看缺失值一共有多少
df.isnull().sum()
### 查看具体确实数值,挨个看缺失值的模式
df[df.出发地.isnull()] #比如出发地,可以看到路线名中包含了出发地和目的地
df.loc[df.出发地.isnull(), '出发地'] = [str(x).split('-')[0] for x in df.loc[df.出发地.isnull(), '路线名']]
df.loc[df.目的地.isnull(), '目的地'] = [str(x).split('-')[1][:2] for x in df.loc[df.目的地.isnull(), '路线名']]
## (b) 缺失值处理
null_index = df[df['价格'].isnull()].index #记录一下空缺值索引,这样后面可以进行对比
### 方法一:直接删除缺失值
df1 = df.copy() #因为要讨论多种方法,所以复制一下原表
df1.dropna(axis=0,how='any',inplace=True) # inplace是否原地替换
df1.shape
### 方法二:取均值
# 思考:直接填充均值是否太随便了,能不能用【出发地,目的地,去程航司,时间,去程方式】进行预测
df2 = df.copy()
df2[df2['价格'].isnull()]
df2['价格'].fillna(round(df2['价格'].mean(),0), inplace = True)
df2['节省'].fillna(round(df2['节省'].mean(),0), inplace = True)
### 方法三:随机森林进行填补
null_index = df[df['价格'].isnull()].index #记录一下空缺值索引,等会可以看一下拟合结果是否离谱
df3 = df.copy()
#生成虚拟变量
dummy = pd.get_dummies(df3[['出发地','目的地','去程方式','航空公司']], prefix=None, prefix_sep='_')
dummy['key']=[x for x in range(len(dummy))]
#获取数值变量
df_sub = df3[['价格','minute']]
df_sub['key']=[x for x in range(len(df_sub))]
#合并
df_merge = pd.merge(df_sub,dummy,on=['key','key'])
from sklearn.ensemble import RandomForestRegressor
# 随机模型预测
# 分成已知和未知价格数据
known_price = df_merge[df_merge['价格'].notnull()].values
unknown_price = df_merge[df_merge['价格'].isnull()].values
y = known_price[:,0]
X = known_price[:,1:]
#进行拟合
model = RandomForestRegressor(random_state=0, n_estimators=2000,n_jobs=-1)
model.fit(X,y)
#预测
predictedPrice = model.predict(unknown_price[:, 1:])
df3.loc[(df3['价格'].isnull()),'价格'] = predictedPrice
# 对比方法2和3
df2['key'] = [x for x in range(len(df2))]
df3['key'] = [x for x in range(len(df3))]
comparison = pd.merge(df2[['key','价格']],df3[['key','价格']],on=['key','key'])
comparison.iloc[null_index,:]
这里的数值处理推荐这个博客:【Python数据分析基础】: 数据缺失值处理 - 码农教程
以及推荐一个jupyter快捷键博客:https://blog.csdn.net/baidu_26137595/article/details/124063900