最在参加了一个机器学习的竞赛,又开始频繁的使用pandas做数据的处理。发现了一些之前没有发现的pandas用法。在这里做一个总结, 也算是学习笔记吧。本笔记大部分都会以下面的数据作为例子。另外,推荐大家使用ipython来查看及处理数据。
首先看这样的数据。
这是kaggle上的关于员工离职的数据,现在要根据满意度,工作项目, 薪水等指标判断一个员工是否会离职。 在进行机器学习之前,我们首先要进行数据的清理及预处理。数据下载
1. 查看统计数据
csv文件读取
拿到数据以后,一般都要先看看数据长啥样,有多大,都有什么特征,用pandas查看这些是非常方便的。针对本例子中的csv文件, 我们使用read_csv函数来读取, 读进来之后是pandas中的DataFrame格式。
import numpy as np
import pandas as pd
# 使用read_csv读取数据
hr = pd.read_csv("HR.csv")
但有一点要注意,读取的时候要先看一下csv文件中格式。主要看两点,一是第一列(也有可能是前几列)是不是索引,二是看第一行是数据还是feature的名称。 read_csv方法默认会将第一行当成feature来解析。
# 如果第一列是索引
pd.read_csv('data.csv', index_col=0)
# 如果是纯数据没有feature的话
pd.read_csv('data.csv', header=None)
实际上如果你用的是ipython,可以直接输入 pd.read_csv? 来查看这个函数的文档,非常方便。
查看数据
# 查看数据的行数与列书, 一般来说行代表样本数, 列代表feature数
hr.shape
# 查看数据的前5行
hr.head()
# 查看每一列的计数及数据类型等信息
hr.info()
# 查看统计信息
hr.describe()
一般来说我们都会看一下这些信息。 从而对数据有一定的概念。
2. 简单的可视化
pandas提供了一个简单的函数让我们可以非常简单的查看各个column的分布直方图,当然仅限于该column的值的数字的时候,如果是离散值就没有用这个办法可视化了。值得注意的是该函数依赖于matplotlib, 须先导入该包。
import matplotlib.pyplot as plt
hr.hist(grid=False, figsize=(12,12))
有两个参数值得一提
grid : True 或者 False; 就是设不设置网格, 这个就看个人的需求了
figsize: tuple;图的大小, 当你绘制的直方图有多个时, 就设置大一点,这个多尝试几次就好了
至于其他的参数,一般来说用的不多, 但如果有需求可以看一下文档,强烈建议用ipython,这用就可以直接用 hr.hist? 来查看该函数的文档了。
3. 去除重复项
pandas提供了duplicated 函数供我们查看是否有完全一样的两行,也就是重复的两行,返回的是一个Boolean值的Series,重复项那里就是True,无重复项的False
# 可以通过df.duplicated()查看是否有重复项
hr.duplicated(keep="last")
keep: "first", "last", False. 默认是"first". 非常重要的参数,first的意思就是重复项里面第一个为False, 剩下的事True, last的意思则正好相反,最后一项是False, 其他重复项为True。指定为False则表示把所有重复项都设置为True
subset: list, 要检查重复的项,默认是全部,也就是两行完全一样才判断为True。 如果只是像查看部分column是否一样的话就可以用subset这个参数了。
除了查看重复的项,我们还可以去除重复项。drop_duplicates提供了这一功能。
hr = hr.drop_duplicates()
keep: "first", "last", False. 默认是“first”。 也就是默认保留最前面的重复项,将其他重复项去除。“last”则表示保留最后面的重复项,将其他重复项去除。False则表示将所有重复项全部去除。
subset: list, 默认是全部列。如果只是要将其中几列相同就去除的话可以用这个参数。
inplace: True or False。 默认是False,也就是不修改原来的DataFrame。设置为True则会改变原来的DataFrame。
4. 处理缺失值
缺失值的处理一直是数据处理的一个重点工作。根据数据的不同会做出不同的选择,有用均值填充的,中位数填充的,用0填充的,甚至直接去除的。再复杂一点的可以用autoencoder来训练预测缺失值,关于缺失值的处理可以写一本厚厚的书了。这里就简单的说明一下常见的处理方法。注意我这个数据没有缺失值,大家可以找找其他数据试一下。
# 用均值填充
hr.fillna(hr.mean())
# 用中位数填充
hr.fillna(hr.median())
# 用0填充
hr.fillna(0)
5. 离散的feature处理
包含离散的feature的数据无法直接作为输入进行机器学习。例如性别,男跟女,例如工资,low,medium,high。 需要做一个向量化处理。有人说不能直接用0,1,2来表示吗,例如0表示low,1表示medium, 2表示high。emmmm,当然不行。怎么向量化呢?以该数据中的工作岗位与工资为例, 001 表示low ,010表示medium,100表示表示high。
categorical_features = ['sales', 'salary']
hr_cat = pd.get_dummies(hr[categorical_features])
hr = hr.drop(categorical_features, axis=1)
hr = pd.concat([hr, hr_cat], axis=1)
很简单的代码,值得一提的事get_dummies这个函数。该函数的作用是将离散的变量转化为向量化,一两句说不清,这里只告诉你可以这么处理离散变量,想要细细了解看一下文档就明白了,我把文档贴过来也没有意思。
6. 数据归一化
向量归一化也是非常重要的。最常见的归一化方法有两种,一种是min-max归一化,就是每一个值除以最大值减去最小值的差,这样可以把数据归一化到[0,1]之间。另一种是z-score标准化,也就是经过处理后的数据符合标准正态分布,即均值为0,标准差为1。这两种都非常常见,具体使用哪种得看数据。可以用sklearn来进行处理,这样就不用自己来实现了。
from sklearn.preprocessing import StandardScaler
# 使用z-score标准化数据
ss = StandardScaler()
scale_features = ['number_project', 'average_monthly_hours', 'time_spend_company']
hr[scale_features] = ss.fit_transform(hr[scale_features])
如果是想用min-max归一化的话,sklearn也有现有的类实现。
from sklearn.preprocessing import MinMaxScaler
ss = MinMaxScaler()
scale_features = ['number_project', 'average_monthly_hours', 'time_spend_company']
hr[scale_features] = ss.fit_transform(hr[scale_features])
7. 去除缺失比例超过50%的行/列
这是我在处理其他数据的时候遇到的问题, 就是有时候并不只是单纯的根据一部分column来去除数据,而是要根据缺失比例来进行取舍。有可能是缺失比例超过30%,或者70%。我查了一下pandas好像没有现有的函数直接实现的。但不打紧,我写了两个函数来实现。
- 去除缺失值比例超过一定程度的列
def drop_col(df, cutoff=0.4):
n = len(df)
for column in df.columns:
cnt = df[column].count()
if (float(cnt) / n) < cutoff:
df = df.drop(column, axis=1)
return df
hr = drop_col(hr)
当然本文中数据是没有缺失值的,因此没有什么效果。注意cutoff指的是有数据的比例。
- 去除缺失值超过一定比例的行
def drop_row(df, cutoff=0.8):
n = df.shape[1]
for row in df.index:
cnt = df.loc[row].count()
if cnt / n < cutoff:
df = df.drop(row, axis=0)
return df
hr = drop_row(hr)
同样的,这里的cutoff也是只有数据的比例
8. 根据条件给列数据重新赋值
这个应该也是非常常见的功能。举个简单的例子,现在要把Work_accident中大于2的值改为True,小于等于2的值改为False。例子要求可能不太合理,但意思应该表达出来了。这种要求怎么实现呢。非常简单,一句就可以搞定了。
hr['Work_accident'] = hr['Work_accident'].apply(lambda x: False if x<2 else True)
如果要求比较复杂,就不要用匿名函数了,自己写一个函数,然后像上面那样子就成了。非常简单的。
大致应该讲完了常见的数据预处理,如果再工作中遇到新的需求,我会不定期的更新本文