目录
一、Pandas 的主要方法
1、基础使用
2、astype()、describe() 、value_counts()
3、排序
4、索引和获取数据
5、应用函数到单元格、列、行
二、分组(Groupby)
1、Pandas 下分组数据的一般形式为:
2、实例中的使用
三、汇总表
1、透视表
Pandas 中的透视表定义如下
实例中的使用
2、交叉表
Pandas中交叉表的定义
实例中的使用
四、增减 DataFrame 的行列
五、预测离网率
总结
该部分的学习基于蓝桥云上的机器学习开放基础课,本章的学习链接:
https://www.lanqiao.cn/courses/1283/learning/
本篇通过分析电信运营商的客户离网率数据集来熟悉 Pandas 数据探索的常用方法,并构建一个预测客户离网率的简单模型。
知识点:排列、索引、交叉表、透视表、数据探索
用到的结构:
练习到的方法:
read_csv():读取数据
head()
:查看前五行info():
输出 DataFrame 的一些总体信息astype()
:更改列的类型describe()
:显示数值特征(int64
和 float64
)的基本统计学特性,如未缺失值的数值、均值、标准差、范围、四分位数等value_counts()
:查看类别(类型为 object )和布尔值(类型为 bool )特征。DataFrame['Name']
:得到一个单独的列(Name为列名)apply():里面跟一个方法或操作
map():
通过一个 {old_value:new_value} 形式的字典替换某一列中的值repalce()
:替换pivot_table()
:建立透视表crosstab()
:构建交叉表insert()
:添加列drop()
:删除列和行Pandas 是基于 NumPy 的一种工具,提供了大量数据探索的方法。Pandas 可以使用类似 SQL 的方式对 .csv、.tsv、.xlsx 等格式的数据进行处理分析。
Pandas 主要使用的数据结构是 Series 和 DataFrame 类。下面简要介绍下这两类:
import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
read_csv()
方法读取数据,然后使用 head()
方法查看前 5 行数据。#read_csv() 读取数据方法
df = pd.read_csv('https://labfile.oss.aliyuncs.com/courses/1283/telecom_churn.csv')
# hand()查看前5行数据
df.head()
运行结果:
上图中的每行对应一位客户,每列对应客户的一个特征。
df.shape
运行结果:
(3333, 20)
上述结果表明,我们的列表包含 3333 行和 20 列。
df.columns
运行结果:
Index(['State', 'Account length', 'Area code', 'International plan', 'Voice mail plan', 'Number vmail messages', 'Total day minutes', 'Total day calls', 'Total day charge', 'Total eve minutes', 'Total eve calls', 'Total eve charge', 'Total night minutes', 'Total night calls', 'Total night charge', 'Total intl minutes', 'Total intl calls', 'Total intl charge', 'Customer service calls', 'Churn'], dtype='object')
info()
方法输出 DataFrame 的一些总体信息。df.info()
运行结果:
RangeIndex: 3333 entries, 0 to 3332 Data columns (total 20 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 State 3333 non-null object 1 Account length 3333 non-null int64 2 Area code 3333 non-null int64 3 International plan 3333 non-null object 4 Voice mail plan 3333 non-null object 5 Number vmail messages 3333 non-null int64 6 Total day minutes 3333 non-null float64 7 Total day calls 3333 non-null int64 8 Total day charge 3333 non-null float64 9 Total eve minutes 3333 non-null float64 10 Total eve calls 3333 non-null int64 11 Total eve charge 3333 non-null float64 12 Total night minutes 3333 non-null float64 13 Total night calls 3333 non-null int64 14 Total night charge 3333 non-null float64 15 Total intl minutes 3333 non-null float64 16 Total intl calls 3333 non-null int64 17 Total intl charge 3333 non-null float64 18 Customer service calls 3333 non-null int64 19 Churn 3333 non-null bool dtypes: bool(1), float64(8), int64(8), object(3) memory usage: 498.1+ KB
bool
、int64
、float64
和 object
是该数据库特征的数据类型。这一方法同时也会显示是否有缺失值,上述结果表明在该数据集中不存在缺失值,因为每列都包含 3333 个观测,和我们之前使用 shape
方法得到的数字是一致的。
2、astype()、describe()
、value_counts()
astype()
方法可以更改列的类型,下列公式将 Churn 离网率 特征修改为 int64
类型。df['Churn'] = df['Churn'].astype('int64')
describe()
方法可以显示数值特征(int64
和 float64
)的基本统计学特性,如未缺失值的数值、均值、标准差、范围、四分位数等。df.describe()
运行结果:
df.describe(include=['object', 'bool'])
运行结果:
value_counts()
方法可以查看类别(类型为 object )和布尔值(类型为 bool )特征。让我们看下 Churn 离网率 的分布。df['Churn'].value_counts()
运行结果:
0 2850 1 483 Name: Churn, dtype: int64
上述结果表明,在 3333 位客户中, 2850 位是忠实客户,他们的 Churn
值为 0。调用 value_counts()
函数时,加上 normalize=True
参数可以显示比例。
df['Churn'].value_counts(normalize=True)
运行结果:
0 0.855086 1 0.144914 Name: Churn, dtype: float64
df.sort_values(by='Total day charge', ascending=False).head()
运行结果:
df.sort_values(by=['Churn', 'Total day charge'],
ascending=[True, False]).head()
运行结果:
使用 DataFrame['Name']
可以得到一个单独的列。比如,离网率有多高?
df['Churn'].mean()
运行结果:
0.14491449144914492
对一家公司而言,14.5% 的离网率是一个很糟糕的数据,这么高的离网率可能导致公司破产。
布尔值索引同样很方便,语法是 df[P(df['Name'])]
,P 是在检查 Name 列每个元素时所使用的逻辑条件。这一索引的输出是 DataFrame 的 Name 列中满足 P 条件的行。
(1)离网用户的数值变量的均值是多少?
df[df['Churn'] == 1].mean()
运行结果:
Account length 102.664596 Area code 437.817805 Number vmail messages 5.115942 Total day minutes 206.914079 Total day calls 101.335404 Total day charge 35.175921 Total eve minutes 212.410145 Total eve calls 100.561077 Total eve charge 18.054969 Total night minutes 205.231677 Total night calls 100.399586 Total night charge 9.235528 Total intl minutes 10.700000 Total intl calls 4.163561 Total intl charge 2.889545 Customer service calls 2.229814 Churn 1.000000 dtype: float64
(2)离网用户在白天打电话的总时长的均值是多少?
df[df['Churn'] == 1]['Total day minutes'].mean()
运行结果:
206.91407867494814
(3)未使用国际套餐(International plan == NO
)的忠实用户(Churn == 0
)所打的最长的国际长途是多久?
df[(df['Churn'] == 0) & (df['International plan'] == 'No')
]['Total intl minutes'].max()
运行结果: 18.9
loc
方法为通过名称索引,iloc
方法为通过数字索引。(1)通过 loc
方法输出 0 至 5 行、State 州 至 Area code 区号 的数据。
df.loc[0:5, 'State':'Area code']
运行结果:
(2)通过 iloc
方法输出前 5 行的前 3 列数据(和典型的 Python 切片一样,不含最大值)。
df.iloc[0:5, 0:3]
df[:1]
和 df[-1:]
可以得到 DataFrame 的首行和末行。df[-1:]
运行结果:
通过 apply()
方法应用函数 max
至每一列,即输出每列的最大值。
df.apply(np.max)
运行结果:
State WY Account length 243 Area code 510 International plan Yes Voice mail plan Yes Number vmail messages 51 Total day minutes 350.8 Total day calls 165 Total day charge 59.64 Total eve minutes 363.7 Total eve calls 170 Total eve charge 30.91 Total night minutes 395 Total night calls 175 Total night charge 17.77 Total intl minutes 20 Total intl calls 20 Total intl charge 5.4 Customer service calls 9 Churn 1 dtype: object
apply()
方法也可以应用函数至每一行,指定 axis=1 即可。在这种情况下,使用 lambda
函数十分方便。比如,下面函数选中了所有以 W 开头的州。df[df['State'].apply(lambda state: state[0] == 'W')].head()
运行结果:
map()
方法可以通过一个 {old_value:new_value} 形式的字典替换某一列中的值。d = {'No': False, 'Yes': True}
df['International plan'] = df['International plan'].map(d)
df.head()
运行结果:
repalce()
方法一样可以达到替换的目的。df = df.replace({'Voice mail plan': d})
df.head()
运行结果:
df.groupby(by=grouping_columns)[columns_to_show].function()
对上述函数的解释:
groupby()
方法根据 grouping_columns 的值进行分组。在下面的例子中,我们根据 Churn 离网率 变量的值对数据进行分组,显示每组的统计数据。
columns_to_show = ['Total day minutes', 'Total eve minutes',
'Total night minutes']
df.groupby(['Churn'])[columns_to_show].describe(percentiles=[])
运行结果:
agg()
,通过 agg()
方法对分组后的数据进行聚合。columns_to_show = ['Total day minutes', 'Total eve minutes',
'Total night minutes']
df.groupby(['Churn'])[columns_to_show].agg([np.mean, np.std, np.min, np.max])
运行结果:
透视表(Pivot Table)是电子表格程序和其他数据探索软件中一种常见的数据汇总工具。它根据一个或多个键对数据进行聚合,并根据行和列上的分组将数据分配到各个矩形区域中。
通过 pivot_table()
方法可以建立透视表,其参数如下:
现在,通过 pivot_table()
方法查看不同区号下白天、夜晚、深夜的电话量的均值。
df.pivot_table(['Total day calls', 'Total eve calls', 'Total night calls'],
['Area code'], aggfunc='mean')
运行结果:
pivot_table()
其他的使用方法见 Pandas 百题大冲关 的透视表部分。
交叉表(Cross Tabulation)是一种用于计算分组频率的特殊透视表,在 Pandas 中一般使用 crosstab()
方法构建交叉表。
pd.crosstab(df['Churn'], df['International plan'])
运行结果:
pd.crosstab(df['Churn'], df['Voice mail plan'], normalize=True)
运行结果:
上述结果表明,大部分用户是忠实用户,同时他们并不使用额外的服务(国际套餐、语音邮件)。
insert()
方法添加列,为所有用户计算总的 Total calls 电话量。 total_calls = df['Total day calls'] + df['Total eve calls'] +
df['Total night calls'] + df['Total intl calls']
# loc 参数是插入 Series 对象后选择的列数
# 设置为 len(df.columns)以便将计算后的 Total calls 粘贴到最后一列
df.insert(loc=len(df.columns), column='Total calls', value=total_calls)
df.head()
运行结果:
df['Total charge'] = df['Total day charge'] + df['Total eve charge'] +
df['Total night charge'] + df['Total intl charge']
df.head()
运行结果:
drop()
方法删除列和行。# 移除先前创捷的列
df.drop(['Total charge', 'Total calls'], axis=1, inplace=True)
# 删除行
df.drop([1, 2]).head()
运行结果:
对上述代码的部分解释:
['Total charge', 'Total calls']
和 axis
参数(1 表示删除列,0 表示删除行,默认值为 0)传给 drop
。inplace
参数表示是否修改原始 DataFrame (False 表示不修改现有 DataFrame,返回一个新 DataFrame,True 表示修改当前 DataFrame)。crosstab()
方法构建一个交叉表来查看 International plan 国际套餐 变量和 Churn 离网率 的相关性,同时使用 countplot()
方法构建计数直方图来可视化结果。# 加载模块,配置绘图
import matplotlib.pyplot as plt
import seaborn as sns
sns.countplot(x='International plan', hue='Churn', data=df)
运行结果:
上图表明,开通了国际套餐的用户的离网率要高很多,这是一个很有趣的观测结果。也许,国际电话高昂的话费让客户很不满意。
pd.crosstab(df['Churn'], df['Customer service calls'], margins=True)
运行结果:
sns.countplot(x='Customer service calls', hue='Churn', data=df)
运行结果:
上图表明,在客服呼叫 4 次之后,客户的离网率显著下降。
df['Many_service_calls'] = (df['Customer service calls'] > 3).astype('int')
pd.crosstab(df['Many_service_calls'], df['Churn'], margins=True)
运行结果:
sns.countplot(x='Many_service_calls', hue='Churn', data=df)
运行结果:
pd.crosstab(df['Many_service_calls'] & df['International plan'], df['Churn'])
运行结果:
上表表明,在客服呼叫次数超过 3 次并且已办理 International Plan 国际套餐 的情况下,预测一名客户不忠诚的准确率(Accuracy)可以达到 85.8%,计算公式如下:
准确率()=++++=2841+192841+9+19+464×100%准确率(Accuracy)=TP+TNTP+TN+FP+FN=2841+192841+9+19+464×100%
其中,TP 表示将 True 预测为 True 的数量,TN 表示将 Flase 预测为 Flase 的数量,FP 表示将 Flase 预测为 True 的数量,FN 表示将 True 预测为 Flase 的数量。
复习一下本次实验的内容:
本次实验使用 Pandas 对数据进行了一定程度的分析和探索,交叉表、透视表等方法的运用将使你在数据探索过程中事半功倍。
相关链接