pandas学习笔记
Pandas 主要使用的数据结构是 Series 和 DataFrame 类。下面简要介绍下这两类:
Series 是一种类似于一维数组的对象,它由一组数据(各种 NumPy 数据类型)及一组与之相关的数据标签(即索引)组成。
DataFrame 是一个二维数据结构,即一张表格,其中每列数据的类型相同。你可以把它看成由 Series 实例构成的字典。
通过 read_csv() 方法读取数据,然后使用** head() **方法查看前 5 行数据。
import warnings
warnings.filterwarnings('ignore')
warnings.filterwarnings('ignore')这行代码的作用是告诉Python忽略所有的警告信息
df = pd.read_csv( 'https://labfile.oss.aliyuncs.com/courses/1283/telecom_churn.csv')
df.head()
read_csv 是 pandas 提供的一个函数,用于读取 CSV(逗号分隔值)文件,并将其转换为 DataFrame 对象,DataFrame 是 pandas 中用于存储和操作结构化数据的主要数据结构。
这里是一些常用的 read_csv 参数:
sep 或 delimiter:指定字段的分隔符,默认为逗号(,)。
header:指定哪一行作为列名,默认是第一行(0索引)。
index_col:指定哪一列作为 DataFrame 的行索引。
usecols:指定需要读取的列。
dtype:指定列的数据类型。
skiprows:指定要跳过的行数或要跳过的行的列表。
nrows:指定要读取的行数。
encoding:指定文件的编码。
df.shape
import pandas as pd
# 假设df是一个已经存在的DataFrame
# df.shape将返回一个形如(rows, columns)的元组
rows, columns = df.shape
print(f"行数: {rows}, 列数: {columns}")
查看一下该数据库的维度、特征名称和特征类型。
'''df.columns的输出将是一个Index对象,
如果你直接打印它,会看到列名被中括号[]包围,
类似于列表,但是你可以使用tolist()方法
将其转换为一个普通的Python列表。'''
columns=df.columns
print(columns)
# 如果你想将列名转换为列表
columns_list = columns.tolist()
print(columns_list)
#例如,如果你想选择特定的列,你可以这样做:
selected_columns = df[['Account length','Total day calls']]
print(selected_columns)
import pandas as pd
# 假设df是一个已经存在的DataFrame
# 例如,通过读取CSV文件创建DataFrame
df = pd.read_csv('path_to_your_file.csv')
# 使用df.info()查看DataFrame的概要信息
df.info()
当你运行 df.info() 时,控制台将输出DataFrame的详细信息,类似于这样:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Column1 100 non-null object
1 Column2 100 non-null int64
2 Column3 100 non-null float64
3 Column4 100 non-null bool
4 Column5 100 non-null datetime64[ns]
dtypes: bool(1), datetime64[ns](1), float64(1), int64(1), object(1)
memory usage: 5.6 KB
信息解析:
<class 'pandas.core.frame.DataFrame'>:表明这是一个DataFrame对象。
RangeIndex: 100 entries, 0 to 99:表明DataFrame有100行,索引从0到99。
Data columns (total 5 columns):表明DataFrame有5列。
Column Non-Null Count Dtype:表格的列,显示列的序号、名称、非空值计数和数据类型。
Non-Null Count:该列非空值的数量。
Dtype:该列的数据类型。
memory usage: 5.6 KB:DataFrame的总内存使用量。
- astype() 方法可以更改列的类型,下列公式将 Churn 离网率 特征修改为 int64 类型。
df['Churn'] = df['Churn'].astype('int64')
- describe() 方法可以显示数值特征(int64 和 float64)的基本统计学特性,如未缺失值的数值、均值、标准差、范围、四分位数等。
df.describe()
通过 include 参数显式指定包含的数据类型,可以查看非数值特征的统计数据
df.describe(include=['object', 'bool'])
- alue_counts() 方法可以查看类别(类型为 object )和布尔值(类型为 bool )特征。
在Pandas中,当你使用value_counts()方法时,返回的Series对象的索引是原始Series中的唯一值,而数据类型(dtype)是这些值出现次数的计数。默认情况下,这些计数是整数,因为它们表示的是数量。
df['Churn'].value_counts()
调用 value_counts() 函数时,加上 normalize=True 参数可以显示比例。
df['Churn'].value_counts(normalize=True)
- 排序
DataFrame 可以根据某个变量的值(也就是列)排序。比如,根据每日消费额排序(设置 ascending=False 倒序排列)。
df.sort_values(by='Total day charge', ascending=False).head()
此外,还可以根据多个列的数值排序。下面函数实现的功能为:先按 Churn 离网率 升序排列,再按 Total day charge 每日总话费 降序排列,优先级 Churn > Tatal day charge。
df.sort_values(by=['Churn', 'Total day charge'],
ascending=[True, False]).head()
- 索引和获取数据
使用 DataFrame['Name'] 可以得到一个单独的列。比如,离网率有多高?
df['Churn'].mean()
布尔值索引同样很方便,语法是 df[P(df['Name'])],P 是在检查 Name 列每个元素时所使用的逻辑条件。这一索引的输出是 DataFrame 的 Name 列中满足 P 条件的行。
让我们使用布尔值索引来回答这样以下问题:离网用户的数值变量的均值是多少?
df[df['Churn'] == 1].mean()
离网用户在白天打电话的总时长的均值是多少
df[df['Churn'] == 1]['Total day minutes'].mean()
未使用国际套餐(International plan == NO)的忠实用户(Churn == 0)所打的最长的国际长途是多久?
df[(df['Churn'] == 0) & (df['International plan'] == 'No')
]['Total intl minutes'].max()
**DataFrame **可以通过列名、行名、行号进行索引。loc 方法为通过名称索引,iloc 方法为通过数字索引。
通过 loc 方法输出 0 至 5 行、State 州 至 Area code 区号 的数据
df.loc[0:5, 'State':'Area code']
通过 iloc 方法输出前 5 行的前 3 列数据(和典型的 Python 切片一样,不含最大值)。
df.iloc[0:5, 0:3]
**
应用函数到单元格、列、行
**
下面通过 apply() 方法应用函数 max 至每一列,即输出每列的最大值。
df.apply(np.max)
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()
分组(Groupby)
Pandas 下分组数据的一般形式为:
df.groupby(by=grouping_columns)[columns_to_show].function()
对上述函数的解释:
groupby() 方法根据 grouping_columns 的值进行分组。
接着,选中感兴趣的列(columns_to_show)。若不包括这一项,那么就会选中所有非 groupby 列(即除 grouping_colums 外的所有列)。
最后,应用一个或多个函数(function)。
在下面的例子中,我们根据 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])
汇总表
Pandas 中的透视表定义如下:
透视表(Pivot Table)是电子表格程序和其他数据探索软件中一种常见的数据汇总工具。它根据一个或多个键对数据进行聚合,并根据行和列上的分组将数据分配到各个矩形区域中。
通过 pivot_table() 方法可以建立透视表,其参数如下:
values 表示需要计算的统计数据的变量列表
index 表示分组数据的变量列表
aggfunc 表示需要计算哪些统计数据,例如,总和、均值、最大值、最小值等。
现在,通过 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() 方法构建交叉表。
构建一个交叉表查看样本的 Churn 离网率 和 International plan 国际套餐 的分布情况。
pd.crosstab(df['Churn'], df['International plan'])
构建一个交叉表查看 Churn 离网率 和 Voice mail plan 语音邮件套餐 的分布情况。
pd.crosstab(df['Churn'], df['Voice mail plan'], normalize=True)
设置 normalize=True 时,你将得到的不是一个简单的频数交叉表,而是一个比例交叉表。
增减 DataFrame 的行列
在 DataFrame 中新增列有很多方法,比如,使用 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()
上面的代码创建了一个中间 Series 实例,即 total_calls,其实可以在不创造这个实例的情况下直接添加列。
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)
sns:这是Seaborn库的常用别名,所以 sns.countplot 就是调用 Seaborn 库中的 countplot 函数。
x='International plan':这个参数指定了x轴上的类别变量,即'International plan'列。这个列包含了分类数据,通常表示客户是否订阅了国际计划。
hue='Churn':这个参数用于指定一个额外的分类变量,用于在同一图表中比较两个子组。在这里,它用于根据'Churn'列的值(通常是'Yes'和'No')来区分颜色,这样可以比较流失客户和未流失客户在国际计划订阅上的差异。
data=df:这个参数指定了数据来源,即Pandas DataFrame df。
同理,查看 Customer service calls 客服呼叫 变量与 Chunrn 离网率 的相关性,并可视化结果。
pd.crosstab(df['Churn'], df['Customer service calls'], margins=True)
将创建一个交叉表(contingency table),该表显示了两个分类变量之间的频数分布,并在表的最后添加了行和列的边际总计(marginal totals)
sns.countplot(x='Customer service calls', hue='Churn', data=df)
为了更好的突出 Customer service call 客服呼叫 和 Churn 离网率 的关系,可以给 DataFrame 添加一个二元属性 Many_service_calls,即客户呼叫超过 3 次(Customer service calls > 3)。看下它与离网率的相关性,并可视化结果。
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)
现在我们可以创建另一张交叉表,将 Churn 离网率 与 International plan 国际套餐 及新创建的 Many_service_calls 多次客服呼叫 关联起来。
pd.crosstab(df['Many_service_calls'] & df['International plan'], df['Churn'])
上表表明,在客服呼叫次数超过 3 次并且已办理 International Plan 国际套餐 的情况下,预测一名客户不忠诚的准确率(Accuracy)可以达到 85.8%,计算公式如下:
准确率(Accuracy)=
TP+TN/TP+TN+FP+FN
(2841+19)/(2841+9+19+464)×100
其中,TP 表示将 True 预测为 True 的数量,TN 表示将 Flase 预测为 Flase 的数量,FP 表示将 Flase 预测为 True 的数量,FN 表示将 True 预测为 Flase 的数量。
复习一下本次实验的内容:
样本中忠实客户的份额为 85.5%。这意味着最简单的预测「忠实客户」的模型有 85.5% 的概率猜对。也就是说,后续模型的准确率(Accuracy)不应该比这个数字少,并且很有希望显著高于这个数字。
基于一个简单的「(客服呼叫次数 > 3) & (国际套餐 = True) => Churn = 1, else Churn = 0」规则的预测模型,可以得到 85.8% 的准确率。以后我们将讨论决策树,看看如何仅仅基于输入数据自动找出类似的规则,而不需要我们手工设定。我们没有应用机器学习方法就得到了两个准确率(85.5% 和 85.8%),它们可作为后续其他模型的基线。如果经过大量的努力,我们仅将准确率提高了 0.5%,那么我们努力的方向可能出现了偏差,因为仅仅使用一个包含两个限制规则的简单模型就已提升了 0.3% 的准确率。
在训练复杂模型之前,建议预处理一下数据,绘制一些图表,做一些简单的假设。此外,在实际任务上应用机器学习时,通常从简单的方案开始,接着尝试更复杂的方案。
实验总结
本次实验使用 Pandas 对数据进行了一定程度的分析和探索,交叉表、透视表等方法的运用将使你在数据探索过程中事半功倍。
浙公网安备 33010602011771号