第二章
第一节 数据清洗及特征处理
数据清洗:对于原始数据中的缺失值、异常值进行处理。相当于数据预处理。
待处理的情况:缺失值、重复值、字符串和数据转换。
-
缺失值
如何查看各列缺失值的情况:
df.info() # 可以查看每一列数据的缺失值情况,及数据类型 df.isnull() # 查看数据表的哪些值是缺失的 df.isnull().sum() # 直接统计缺失情况
检索缺失值:
# 查看Age、Cabin、Embarked列的数据 df[['Age','Cabin','Embarked']].head() # 检索空缺值的三种方式 df[df['Age']==None]=0 df[df['Age'].isnull()]=0 df[df['Age']==np.nan]=0 # 最好使用np.nan。当空缺值的数据类型为float64所以用None索引不到
处理缺失值:
# 方法一:去除存在缺失值的项 df.dropna() # 方法二:使用 0 补全 # df.fillna({'Age':0}) # 该方法中,df本身不会发生改变,因此对其赋值得到新的数据 df = df.fillna({'Age':0}) # 方法三:使用 0 补全(由条件判断进行补全) df.loc[df['Age'].isnull(),'Age'] = 0 # loc函数表示行,即Age一列的哪一行为空,即补0
对整张表的缺失值进行
补0
处理df.fillna(0)
-
重复行
对于整个数据集,可能存在有两条(两行)数据是完全相同的。
# 重复行检索 df.duplicated() # 给出每一条数据是否重复的结果 df[df.duplicated()] # 单独显示重复的数据 # 删除重复行 df = df.drop_duplicates()
-
特征观察与处理
数据特征的分类:
- 数值型:分为离散型和连续型。一般可以直接用于模型的训练。但有时为了模型的稳定性,困难会将离散型变量转换为连续变量。
- 文本型:文本型特征 往往需要转换成数值型特征才可以用于建模分析。
① 分箱处理(离散化处理)
例:本案例中,将年龄【连续
-->
离散】分为五个阶段,每个阶段用一个值来代替。-
年龄均分
cut()
# 将数据按年龄平均分为5个部分: # df['AgeBand'] = pd.cut(df['Age'], 5,labels = [1,2,3,4,5]) # df['AgeBand'] = pd.cut(df['Age'], 5,labels = list('12345')) df['AgeBand'] = pd.cut(df['Age'],[0,5,15,30,50,80],right=False) # cut函数的三个参数:bins()、right(区间是右闭还是右开,默认为True,左开右闭)、labels
分箱操作的优点:
能适应异常值的存在。以年龄为例,若出现300岁的异常数据,分箱之后只会进入最大的分组,而不会通过大数据影响模型。
-
年龄按百分比分类
qcut()
# 按10%、30%、50%、70%、90%分为5个年龄段 df['AgeBand'] = pd.qcut(df['Age'],duplicates = 'drop',[0,0.1,0.3,0.5,0.7,0.9],labels = list('1234')) # duplicates参数:边缘是否唯一(默认为raise,唯一;否则为drop)
②对文本变量进行转换
-
查看文本变量的种类
# 方法一 # 可以查看每一列数据的每一种文本的种类 df.['Sex'].value_counts()
# 方法二 df.['Cabin'].unique()
-
转为数值变量
# 对于文本种类不多的列 # 方法一:直接用`replace()`替换 df['Sex'].replace(['male','female'],[1,2], inplace = True) # inplace=True,直接作用于当前文件本身 #方法二: map,字典 df['Sex_num'] = df['Sex'].map({'male': 1, 'female': 2})
# 对于文本种类过多的列 # 使用sklearn.preprocessing的LabelEncoder from sklearn.preprocessing import LabelEncoder df['Cabin'] = LabelEncoder().fit_transform(df['Cabin'])
-
将类别文本转换为
one-hot编码
若按数值简单对文本进行处理,数值之间的大小没有任何意义,故采用
one-hot编码
:#方法一: OneHotEncoder x = pd.get_dummies(df['Age'], prefix='Age') # 将变换好的年龄数据拼接到原始数据上 df = pd.concat([df, x], axis=1) # 按列拼接
# 进阶:使用循环进行批量处理 for column in ['Cabin', 'Age', 'Embarked'] x = pd.get_dummies(df[column], prefix=column) df = pd.concat([df, x], axis=1)
one-hot编码
中只有0、1,且大部分都是0,因此很有利于提高计算性能。
③【附加问题】从纯文本Name特征里提取出Titles的特征(所谓的Titles就是Mr,Miss,Mrs等)
df['Title'] = df.Name.str.extract('([A-Za-z]+)\.', expand=False) # 参数:正则表达式
第二节 数据重构1
数据重构仍属于数据准备(数据预处理)的范围。
-
数据的合并
-
concat()
横向合并:对于两张表,如果属于左部、右部的不同列的数据,使用
concat()
方法进行数据合并。list_up = [text_left_up,text_right_up] # 两个待合并的数据 result_up = pd.concat(list_up,axis=1) # axis=1, 横向合并(该参数默认为0) list_down=[text_left_down,text_right_down] result_down = pd.concat(list_down,axis=1)
纵向合并:
result = pd.concat([result_up,result_down]) # axis的值默认为0,表示纵向合并
-
DataFrame自带的
join()
和append
# join()相当于concat()的横向合并;append()相当于concat()的纵向合并,即concat()默认方法。 up = text_left_up.join(text_right_up) down = text_left_down.join(text_right_down) result = up.append(down)
-
Pandas的
merge()
和DataFrame的append()
# merge()类似于join(),但额外需要一个共同的列用于拼接,即显示行索引(相同的列) up = text_left_up.merge(text_right_up, left_index = True, right_index = True) down = text_left_down.merge(text_right_down, left_index = True, right_index = True) result = up.append(down)
三者对比:
concat()
可以用于实现行、列的拼接,需要改变的是参数axis
的值,默认使用按行拼接(axis = 0
);join()
和merge()
都只能用于按列拼接,且merge()
的使用多了一个步骤;append()
只能用于按行拼接。
-
-
另一种数据类型 -
Series
stack
和unstack
函数:改变数据集的样式,返回一个重构的数据data2 = data.stack() # 将表格变为“花括号”形式 data3 = data2.unstack() # 将“花括号”形式变为二维表格形式
输出到本地之后的格式:
第三节 数据重构2
-
数据运用
GroupBy机制(分组机制:分隔、应用和组合)
分组之后进行更高一级的运算:最大、小值,求和,均值,中位数,标准差,方差
分组机制拓展:
my_group1=titanic.groupby('pclass') #将数据对乘客所在船舱等级(“pclass”)进行分组 # 此时数据不再是DataFrame对象,而是DataFrameGroupBy对象. my_group1.count() #据此对分组后的数据进行分析 # 或者使用list()来查看每一个group list(my_group1)
# 以不同性别下的存活情况为例,输出存活率与存活人数 my_group2=titanic.groupby('sex') sex_sur=my_group2['survived'].agg(['mean','count']) # 通过传入agg方法选择所需的函数 sex_sur # 可以实现多层分组 my_group2=titanic.groupby(['pclass','sex']) my_group2.agg(['mean','count'])
上述代码运行的结果展示:【多层分组】
# 对方法重命名,方便理解 my_group2=titanic.groupby(['pclass','sex']) my_group2.agg([('均值','mean'),('计数','count')])
① 计算泰坦尼克号男性与女性的平均票价
group = df.groupby('Sex') group.describe() # 显示性别分类下所有属性的详情
df.groupby('Sex')['Age'].describe() # 加上年龄标签,显示性别分类下的年龄情况
df.groupby('Sex')['Age'].mean() # 显示性别分类下的年龄平均值 df.groupby('Sex')['Fare'].mean() # 显示性别分类下的票价平均值
② 统计泰坦尼克号中男女的存活人数
survived_sex = df.groupby('Sex')['Survived'].sum()
③ 计算客舱不同等级的存活人数
survived_pclass = df.groupby('Pclass')['Survived'].sum()
这些运算可以通过
agg()
函数来同时计算。并且可以使用rename()
函数修改列名。方便同时统计多个维度的数据。否则需要经过多次的数据合并,较复杂。
# agg()函数:可以指定多个计算方法 df.groupby('Pclass')['Survived'].agg('sum') # 与上面的结果相同,没有区别 df.df.groupby('Pclass').agg({'Survived':'sum', 'Fare':'mean'}) # 同时对存活人数求和、对票价取平均
# 对于上述计算,为了更直观地进行结果展示,使用rename()函数进行处理 df.df.groupby('Pclass').agg({'Survived':'sum', 'Fare':'mean'}).rename(columns = { 'Survived':'survived_sum','Fare':'fare_mean' })
④统计在不同等级的票中的不同年龄的船票花费的平均值
df.groupby(['Pclass','Age'])['Fare'].mean() # 根据两列进行分类,再统计票价的平均值
⑤ 将①、②数据合并
result = pd.merge(means,survived_sex, on='Sex')
merge()
不可以直接对Series格式的数据进行拼接,需要转为DataFrame格式survived_sex.to_frame() # 即可将Series格式转为DataFrame格式
⑥ 得出不同年龄的总的存活人数,然后找出存活人数最多的年龄段,最后计算存活人数最高的存活率(存活人数/总人数)
#不同年龄的存活人数 survived_age = df.groupby('Age')['Survived'].sum() #找出最大值的年龄段 survived_age[survived_age.values == survived_age.max()] # values指当前键对应的数据的条数 #首先计算存活总人数 _sum = df['Survived'].sum() percent =survived_age.max()/_su
第四节 数据可视化
Matplotlib
:Python数据可视化库绘图方法总结:
plot()默认是折线图;
hist()
直方图;
%matplotlib inline
import matplotlib.pyplot as plt
# from matplotlib import pyplot as plt
展示泰坦尼克号数据集中男女中生存人数分布情况(柱状图)
sex = df.groupby('Sex')['Survived'].sum()
sex.plot.bar()
plt.title('survived_count')
plt.show()
男女中生存人与死亡人数的比例图(柱状图)
df.groupby(['Sex','Survived'])['Survived'].count().unstack().plot(kind='bar',stacked='True')
plt.title('survived_count')
plt.ylabel('count')
# 使用Sex、Survived同时作为分类条件,可以同时获取生存人数和死亡人数
# count():分别计数
# unstack() 将数据变为二维表格的形式
# 0表示死亡,1表示生存
不同票价的人生存和死亡人数分布情况(折线图)
# 计算不同票价中生存与死亡人数 1表示生存,0表示死亡
fare_sur = df.groupby(['Fare'])['Survived'].value_counts().sort_values(ascending=False)
fare_sur
# 排序后绘折线图
fig = plt.figure(figsize=(20, 18))
fare_sur.plot(grid=True)
plt.legend()
plt.show()
票价高的人死亡比例低
不同仓位等级的人生存和死亡人员的分布情况(柱状图)
# 1表示生存,0表示死亡
pclass_sur = df.groupby(['Pclass','Survived'])['Survived'].counts().unstack()
不同年龄的人生存与死亡人数分布情况
# 死亡人数
df.Age[df.Survived == 0].hist(bins=5, alpha=0.5) # 绘制直方图
# 生存人数
df.Age[df.Survived == 1].hist(bins=5, alpha=0.5) # alpha参数:更改透明度
plt.legend({0,1})
plot.xlabel('age')
plot.ylabel('count')
# density参数:根据分布密度绘制直方图。
# 会改变纵坐标刻度,变为密度
df.Age[df.Survived == 0].hist(bins=5, alpha=0.5, density=1)
df.Age[df.Survived == 1].hist(bins=5, alpha=0.5, density=1)
df.Age[df.Survived == 1].plot.density() # 增加密度曲线
df.Age[df.Survived == 0].plot.density()
plt.legend({0,1})
plot.xlabel('age')
plot.ylabel('density')
不同仓位等级的人年龄分布情况(折线图)
# 方法一
df.Age[df.Pclass == 1].plot(kind='kde')
df.Age[df.Pclass == 2].plot(kind='kde')
df.Age[df.Pclass == 3].plot(kind='kde')
plt.xlabel("age")
plt.legend((1,2,3),loc="best")
# 方法二
unique_pclass = df.Pclass.unique()
unique_pclass.sort() # 对获得的数值进行排序
for i in unique_pclass:
df.Age[df.Pclass == i].plot.density()
plt.xlabel('age')
plt.legend(unique_pclass)
# 方法三
import seaborn as sns
for i in unique_pclass:
sns.kdeplot(df.Age[df.Pclass == i], shade=True, linewidth=0)
the end.