数据预处理实战(1)
目录
1. 前言
2. 数据字典
3. 优雅使用pandas
3.1 读取数据
3.2 索引与选取
3.3 布尔索引
3.4 去重
3.5 分组
3.6 数据框的合并
(1)横向合并
(2)纵向合并
3.7 排序(ORDER )与替换(REPALCE)
4. 衍生变量与数据编码
4.1 apply函数
4.2 map函数
5. 数据描述
6. 数据质量
6.1 缺失值
6.2 异常
7. 数据分箱(离散化)
1、前言
数据挖掘的关键在于数据的处理,业间有句话大概就是说模型的特征决定了该模型上限,而参数只是不断接近这个上限而已。还有一句话“机器学习就像中药,而调参就是神农尝百草”,说明调参只是在无数可能性中找出最优(最合适)的一组参数值,不同问题有不同的最优参数,当然我们在考虑最优参数的同时仍要考虑时间成本,也不能说针对某个问题做个模型花了几个月,到那时候可能用户情况又变化了,所以最好的模型就是快狠准。该系列主要记录如何用python的pandas做数据预处理的一些技巧,包括数据质量检查与清洗(缺失与异常值)、数据探索等方面内容。
2、数据字典
|变量 | 定义| 说明|
| :-------------: |:-------------:| : -----:|
|survival | 是否幸存 | 0 = No, 1 = Yes |
|pclass| 船舱等级| 1 = 1st, 2 = 2nd, 3 = 3rd |
|sex | 性别| |
|Age | 年龄| |
|sibsp| 有多少兄弟姐妹一起乘船 | |
|parch|有 多少父母与儿子一起乘船 | |
|ticket| 船票编号| |
|fare | 船票价格| |
|cabin| 舱数量| |
|embarked| 上船地点| C = Cherbourg, Q = Queenstown, S = Southampton|
注:基础数据为:kaggle案例——泰坦尼克号。
3、优雅使用pandas
3.1 读取数据
import pandas as pd
df_titanic = pd.read_csv('C:/Users/whenif/Desktop/titanic_train.csv')
原始数据框
3.2 索引与选取
类似SQL的SELECT语句,主要包括以下函数调用:
- loc——通过行标签索引行数据
- iloc——通过行号获取行数据
- ix——结合前两种的混合索引
import copy
df_titanic_tmp = copy.deepcopy(df_titanic.iloc[0:5])#选取前五列作为实验
df_titanic_tmp.index = ['a','b','c','d','e']#修改索引名
df_titanic_tmp.columns
df_titanic_tmp.rename(columns={'PassengerId': 'haha'}, inplace=True)#修改列名名
根据行与列的可能情况做组合,一般的选取有以下四种情况。
#选取某一行所有列
df_titanic_tmp.loc['a']
df_titanic_tmp.iloc[1]
df_titanic_tmp.ix['a']
df_titanic_tmp.ix[1]
#选取某一列所有行
df_titanic_tmp['Survived']
df_titanic_tmp[['Survived','Pclass']]
df_titanic_tmp.loc[:,['Survived']]
df_titanic_tmp.iloc[:,1]
df_titanic_tmp.ix[:,['Survived']]
df_titanic_tmp.ix[:,1]
#选取某一行所有列
df_titanic_tmp.loc['a',:]
df_titanic_tmp.iloc[0,:]
df_titanic_tmp.ix['a',:]
df_titanic_tmp.ix[0,:]
#选取某些列某些行
df_titanic_tmp.loc['a':'c','Survived':'Name']
df_titanic_tmp.iloc[0:2,1:3]
df_titanic_tmp.ix['a':'c','Survived':'Name']
df_titanic_tmp.ix[0:2,1:3]
3.3 布尔索引
类似SQL中的WHERE语句。
实现:基于某些列的条件筛选另一列的值,你会怎么做?
#AND(&)
df_titanic_tmp.loc[(df_titanic_tmp['Survived']==1)
& (df_titanic_tmp['Pclass']>=2)
, ['Survived','Pclass','Name']]
#OR(|)
df_titanic_tmp.loc[(df_titanic_tmp['Survived']==1)
| (df_titanic_tmp['Pclass']>=2)
, ['Survived','Pclass','Name']]
#IN(isin)/NOT(-)
df_titanic_tmp.loc[-((df_titanic_tmp['Pclass'].isin([1,2])))
, ['Survived','Pclass','Name']]
#包含字符串
df_titanic_tmp.loc[(df_titanic_tmp.Name.str.contains('Miss'))
, ['Survived','Pclass','Name']]
#取筛选后第一行数据(TOP 1)
df_titanic_tmp.loc[(df_titanic_tmp.Name.str.contains('Miss'))
, ['Survived','Pclass','Name']].values[0]
3.4 去重
df_titanic_tmp.drop_duplicates(subset=['Survived'], keep='first', inplace=False).iloc[:,1]
- subset:为选定的列做distinct,默认为所有列;
- keep:值选项{'first', 'last', False},保留重复元素中的第一个、最后一个,或全部删除;
- inplace:默认为False,返回一个新的dataframe;若为True,则返回去重后的原dataframe。
3.5 分组
类似SQL中的GROUP函数。
import numpy as np
df_titanic_tmp.groupby('Survived').size()
df_titanic_tmp.groupby('Survived').count()
df_titanic_tmp.groupby('Survived').agg({'Sex': np.sum})
df_titanic_tmp.groupby('Survived').agg({'Sex': np.max})
df_titanic_tmp.groupby('Survived').agg({'Sex': pd.Series.nunique})
3.6 数据框的合并
类似于SQL中的JOIN模式,可实现左连接、右连接、内连接、全连接等。
(1)横向合并
df_titanic_tmp1 = copy.deepcopy(df_titanic_tmp)
df_titanic_tmp1.rename(columns={'Name': 'Name1'}, inplace=True)
pd.merge(df_titanic_tmp, df_titanic_tmp1, how='left', left_on='Name', right_on='Name1')
(2)纵向合并
pd.concat([df_titanic_tmp,df_titanic_tmp1])
3.7 排序(ORDER )与替换(REPALCE)
df_titanic_tmp.sort_values(['Survived', 'Pclass'], ascending=[False, True])
df_titanic_tmp['Survived'].replace(to_replace=3, value=33, inplace=True)
df_titanic_tmp.replace({'Survived': {3: 33, 4: 44}}, inplace=True)
4、衍生变量与数据编码
4.1 apply函数
df_titanic['Fare2'] = df_titanic['Fare'].apply(
lambda x: 0 if x <= 0 else x)
def each_len(x):
return len(x)
print(df_titanic.apply(each_len, axis=0))#axis=0代表函数应用于每一列
4.2 map函数
#女生用1,男生用2表示
sex_mapping = {
'female': 1,
'male': 2
}
df_titanic['Sex'] = df_titanic['Sex'].map(sex_mapping)
5、数据描述
train_data = df_titanic.iloc[:,[1,2,4,5,6,7,9,11]]
import numpy as np
data_explore = train_data.describe().T
data_explore['null'] = len(train_data)-data_explore['count']#describe自动计算非空值数量
6、数据质量
6.1 缺失值
#直接删除
train_data.dropna()#默认情况下,dropna会删除任何含有缺失值的行
train_data.dropna(how='all') #只删除所有行为缺失值的观测
#用0填补所有缺失值
train_data.fillna(0)
#采用前项填充或后向填充
train_data.fillna(method='ffill') #前一个观察值填充
train_data.fillna(method='bfill') #前一个观察值填充
#使用常量填充不同的列或#用均值或中位数填充各自的列
train_data.fillna({'Age':int(train_data['Age'].mean()),'Embarked':3},inplace=True)
6.2 异常值
def binning(col, cut_points, labels=None):
minval = col.min()
maxval = col.max()
#利用最大值和最小值创建分箱点的列表
break_points = [minval] + cut_points + [maxval]
#如果没有标签,则使用默认标签0 ... (n-1)
if not labels:
labels = range(len(cut_points)+1)
#使用pandas的cut功能分箱
colBin = pd.cut(col,bins=break_points,labels=labels,include_lowest=True)
return colBin
#为年龄分箱:
cut_points = [30,50,70]
#labels = ["low","medium","high","very high"]
train_data["Age_bin"] = binning(train_data["Age"], cut_points)
print(pd.value_counts(train_data["Age_bin"], sort=False))
7、数据分箱(离散化)
def binning(col, cut_points, labels=None):
minval = col.min()
maxval = col.max()
#利用最大值和最小值创建分箱点的列表
break_points = [minval] + cut_points + [maxval]
#如果没有标签,则使用默认标签0 ... (n-1)
if not labels:
labels = range(len(cut_points)+1)
#使用pandas的cut功能分箱
colBin = pd.cut(col,bins=break_points,labels=labels,include_lowest=True)
return colBin
#为年龄分箱:
cut_points = [30,50,70]
#labels = ["low","medium","high","very high"]
train_data["Age_bin"] = binning(train_data["Age"], cut_points)
print(pd.value_counts(train_data["Age_bin"], sort=False))
参考与拓展阅读:
[1]Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)
[2]用 Python 做数据处理必看:12 个使效率倍增的 Pandas 技巧(上)
[3]用 Python 做数据处理必看:12 个使效率倍增的 Pandas 技巧(下)
[4]【分析篇】:Pandas像sql操作python 进行数据分析
[5]数据分析之pandas学习