用python进行数据分析(二:数据处理)
四、数据处理
(1)缺失值
查看缺失情况:
1 data.isnull()#查看所有缺失值 2 data.isnull().any()#获取含有缺失值的列 3 data.isnull().all()#获取全部为NA的列
删除缺失值:
data2=data.dropna()
利用sklearn替换缺失值。当缺失值为数值型数据时,可用利用均值来替换
data.index=data[\'name\']#将第一列作为索引data=data.drop([\'name\'],axis=1)#删除第一列 nan_model=Imputer(missing_values=\'NaN\',strategy=\'mean\',axis=0)#按照行均值替换对应缺失值。 nan_result=nan_model.fit_transform(data)
利用pandas替换缺失值(常用)
data.fillna(0) #缺失值用0替换 data.fillna(method=\'pad\')#用前面的值替换 data.fillna(method=\'backfill\')#用后面的值替换
一个实例(https://blog.csdn.net/weixin_41576911/article/details/83744417):
import pandas as pd
import numpy as np
from sklearn.preprocessing import Imputer
df = pd.DataFrame(np.random.randn(6,4),columns = list(\'abcd\'))
df.iloc[4,3] = np.nan#iloc是选择行和列
df.loc[3] = np.nan#loc是选择行
print(df)
print(df.loc[0:2,3])
nan_all=df.isnull()
print(nan_all)
drop = df.dropna()#丢弃包含缺失值的行记录
print(drop)
又一个实例(https://www.jianshu.com/p/d750ba9075dd,写得比我清楚,强推!):
# 删除完全缺失的行,若不指定参数how,则删除的是所有含有nan的行
>>> data.shape
(6578, 7)
>>> data_drop_nan = data.dropna(how=\'all\')
>>> data_drop_nan.shape
(6577, 7)
>>> data.dropna().shape
(6575, 7)
# 对部分缺失行进行填充
# 用后一行的值填充前一行的缺失值
>>> data_drop_nan.fillnan(method=\'backfill\')
# 对指定列填充指定值
>>> data_drop_na.fillna({\'购药时间\':\'2018-01-20 星期三\', \'社保卡号\': \'1.338953e+07\'})
另一个例子(https://blog.csdn.net/wangxingfan316/article/details/79363420),是将price为0的值改为了36:
data[\'price\'][data[\'price\']==0]=None
x = 0
for i in data.columns:
for j in range(len(data)):
if (data[i].isnull()) [j]:
data[i][j]=\'36\'
x+=1
print(x)
(2)数据不平衡
首先是SMOTE函数的使用,推荐博文:https://www.cnblogs.com/xyou/p/9075443.html(特详细)
使用的例子:
from imblearn.over_sampling import SMOTE
#eg1
X_resampled_smote, y_resampled_smote = SMOTE().fit_sample(X, y)
#eg2
over_samples = SMOTE(random_state=1234)
over_samples_X,over_samples_y = over_samples.fit_sample(X_train, y_train)
然后是Borderline-SMOTE(来源:https://www.cnblogs.com/kamekin/p/9824294.html),原始的SMOTE是对所有少数类样本生成新样本。而改进的方法则是先根据规则判断出少数类的边界样本,再对这些样本生成新样本。
SMOTE函数中的kind参数控制了选择哪种规则:
borderline1:最近邻中的随机样本与该少数类样本a来自于不同的类;
borderline2:最近邻中的随机样本可以是属于任何一个类的样本;
svm:使用支持向量机分类器产生支持向量然后再生成新的少数类样本。
实现:
from imblearn.under_sampling
import ClusterCentroids
cc = ClusterCentroids(random_state=0)
X_resampled, y_resampled = cc.fit_sample(X, y)
(3)重复值处理
(原文:https://blog.csdn.net/maymay_/article/details/80197629 )
pandas 的duplicated可以查看重复值,,duplicated函数用于标记Series中的值、DataFrame中的记录行是否是重复,重复为True,不重复为False。
语句为:
1 pandas.DataFrame.duplicated(self, subset=None, keep=’first’)
subset:用于识别重复的列标签或列标签序列,默认所有列标签
keep=‘frist’:除了第一次出现外,其余相同的被标记为重复
keep=’last’:除了最后一次出现外,其余相同的被标记为重复
keep=False:所有相同的都被标记为重复
重复值删除:
pandas 里面 drop_duplicates 、drop_duplicates函数用于删除Series、DataFrame中重复记录,并返回删除重复后的结果
pandas.DataFrame.drop_duplicates(self, subset=None, keep=’first’, inplace=False)
pandas.Series.drop_duplicates(self, keep=’first’, inplace=False)
(4)判断字符串中是否包含目标字符串
可以用pandas的str.contains 判断,返回boolean Series
(dataframe.colname.str.contains("somestring")).sum
(5)值替换
可以用map进行映射map(function, iterable, …)会根据提供的函数对指定序列做映射。
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
dataframe["newcol"] = dataframe.somecol.map{ {"female":0 , "male": 1} )
import numpy as np
data.replace([-999,-1000], np.nan) data.replace({-999: np.nan, -1000:0})
(6)异常值
方法1,异常值的重新赋值
#异常值处理
da = data.values#重新赋值data
#异常值处理,将commments大于200000的数据comments设置为58
cont_clou = len(da)#获取行数
#遍历数据进行处理
for i in range(0,cont_clou):
if(data.values[i][3]>200000):
#print(data.values[i][3])
da[i][3]=\'58\'
#print(da[i][3])
方法二,
特征工程中的RobustScaler
方法,在做数据特征值缩放的时候,它会利用数据特征的分位数分布,将数据根据分位数划分为多段,只取中间段来做缩放,比如只取25%分位数到75%分位数的数据做缩放。这样减小了异常数据的影响。
优缺点:(1)有坚实的统计学理论基础,当存在充分的数据和所用的检验类型的知识时,这些检验可能非常有效;(2)对于多元数据,可用的选择少一些,并且对于高维数据,这些检测可能性很差。
(7)数据筛选
利用pandas进行行选择和列选择:
import pandas as pd
data = {\'state\':[\'Ohio\',\'Ohio\',\'Merry\',\'Nevaio\',\'Nevada\'],
\'year\':[2000,2001,2002,2001,2002],
\'pop\':[1.5,1.7,3.6,2.4,2.9]
}
frame = pd.DataFrame(data,columns=[\'year\',\'state\',\'pop\',\'debt\'],index=[\'one\',\'two\',\'three\',\'four\',\'five\'])
找出state中\’state\’列中含有字符\’io\’的行,将其的debt列赋值为\’aa\’:
frame.ix[frame[\'state\'].str.contains(\'io\'),[\'debt\']] = \'aa\'
也可换个写法。如state中\’state\’列中等于‘Ohio’行,将其的debt列赋值为\’aa\’:
frame.ix[frame[\'state\']==\'Ohio\',[\'debt\']] = \'aa\'
多个选择条件时,用(‘&’、‘|’),如现找出state中\’state\’列中等于‘Ohio’行或者‘Merry’的行,用\’|\’,将其的debt列赋值为\’aa\’,实现代码如下:
frame.ix[(frame[\'state\']==\'Ohio\')|(frame[\'state\']==\'Merry\'),[\'debt\']] = \'aa\'
(8)分箱:
#年龄数据
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
# 分箱的边界
bins = [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins)
print(type(cats))
# Categorical对象
cats
#获取分箱编码
cats.codes
#返回分箱便捷索引
cats.categories
#统计箱中元素的个数
pd.value_counts(cats)
#带标签的分箱
group_names = [\'Youth\', \'YoungAdult\', \'MiddleAged\', \'Senior\']
cats = pd.cut(ages, bins, labels = group_names)
cats
cats.get_values()
还可以借用循环进行分箱
def get_period(row):
hour = row[\'起飞时间\'].hour
if hour in range(6,12):
return \'上午\'
elif hour in range(12,18):
return \'下午\'
else:
return \'夜间\'
(9)哑变量操作
df = pd.DataFrame({\'key\': [\'b\', \'b\', \'a\', \'c\', \'a\', \'b\'], \'data1\': range(6)}) df pd.get_dummies(df[\'key\'])
二值化数据是通过阈值将数值转换为二值,大于阈值取值为1,小于阈值取值为0,这个过程又叫二分数据或者阈值转换。
在生成明确值和特征工程中增加属性的时候使用。
Python中使用scikit-learn中的Binarizer实现。
from numpy import set_printoptions from sklearn.preprocessing import Binarizer array=data.values X=array[:,0:8]#分离出输入变量 Y=array[:,8]#分离出输出变量 transformer=Binarizer(threshold=0.0).fit(X) newX=transformer.transform(X) set_printoptions(precision=3) print(newX.head(10))
(10)向量化字符串操作
data = {\'Dave\': \'dave@google.com\', \'Steve\': \'steve@gmail.com\', \'Rob\': \'rob@gmail.com\', \'Wes\': np.nan}
data = pd.Series(data)
data
#字符串列元素中是否包含子字符串
data.str.contains(\'gmail\')
#字符串列切片操作
data.str[:5]
split_df = data.str.split(\'@\', expand=True)
split_df
split_df = data.str.split(\'@\')
split_df
split_df[0].str.cat(split_df[1], sep=\'@\')
(11)衍生变量
pandas使用apply多列生成一列数据的实例:
import pandas as pd
def my_min(a, b):
return min(abs(a),abs(b))
s = pd.Series([10.0247,10.0470, 10.0647,10.0761,15.0800,10.0761,10.0647,10.0470,10.0247,10.0,9.9753,9.9530,9.9353,9.9239,18.92,9.9239,9.9353,9.9530,9.9753,10.0])
df = pd.DataFrame(s)
df.columns=[\'value\']
df[\'val_1\'] = df[\'value\'].diff()
df[\'val_2\'] = df[\'val_1\'].shift(-1)
df[\'val\'] = df.apply(lambda row: my_min(row[\'val_1\'], row[\'val_2\']), axis=1)
map和lambda的搭配使用,可以将两个等长的序列进行运算,生成新的序列。利用这个方法,可以利用DataFrame中已知列的数据生成新列。把col1和col2两个等长的序列代入了function(x,y)函数,两列中对应的数据两两计算,生成了map对象。再用list()函数把map对象转化为序列,就可以填入DataFrame生成一个新列new-col了。具体如下:
df[\'new_col\']=list(map(lambda x,y: function(x,y), df[\'col1\'], df[\'col2\']))
(12)调整数据尺度
如果数据的各个属性按照不同的方式度量数据,就需要调整数据的尺度来让所有数据按照相同的尺度进行度量,这会给机器学习算法的训练带来便利。调整数据尺度通常是将所有的变量进行标准化、或把数据转换为0和1之间的值,这对于回归算法、神经网络及KNN是一种提升准确率的非常有效的方法。在python中,可以用scikit-learm中MinMaxScalar将变量缩小至指定范围,或者是对数据标准化(均值为0方差为1)。
数据尺度的统一,能够提高与距离相关算法的准确度。
from numpy import set_printoptions from sklearn.preprocessing import MinMaxScaler array=data.values X=array[:,0:8]#分离出输入变量 Y=array[:,8]#分离出输出变量 transformer=MinMaxScaler(feature_range=(0,1))#指定转换范围为0到1之间 newX=transformer.fit_transform(X)#数据转换 set_printoptions(precision=3) print(newX.head(10))
(13)正态化处理
正态化数据是有效的处理符合高斯分布的数据的一种手段,其输出结果以0为中位数,方差为1,并作为假定数据符合高斯分布的算法的输入。
适用算法有:线性回归、逻辑回归、线性判别分析等。
Python可以通过scikit-learn的StandardScaler。
from numpy import set_printoptions from sklearn.preprocessing import StandardScaler array=data.values X=array[:,0:8]#分离出输入变量 Y=array[:,8]#分离出输出变量 transformer=StandardScaler().fit(X) newX=transformer.transform(X) set_printoptions(precision=3) print(newX.head(10))
(14)标准化处理
标准化是指将每一行的数据的距离都处理成1,因此称为归一化。适合处理系数数据(比如有很多值都是0)。
标准化对于使用权重输入的算法,如神经网络;或者使用距离的算法,如KNN,都具有明显的准确度提升效果。
Python中是使用scikit-learn中的Normalizer实现。
from numpy import set_printoptions from sklearn.preprocessing import Normalizer array=data.values X=array[:,0:8]#分离出输入变量 Y=array[:,8]#分离出输出变量 transformer=Normalizer().fit(X) newX=transformer.transform(X) set_printoptions(precision=3) print(newX.head(10))