在本文中,将使用与之前相同的数据集,但这次将处理偏斜数据,因为在现实世界项目中,将遇到各种类型的数据。将简要讨论每个库对分析的贡献。NumPy:用于执行主要的数学计算,最好使用预定义的函数应用公式。Pandas:这是数据处理库,帮助处理表格数据框架,即访问和更改相同的数据。Matplotlib:这是数据可视化库,帮助可视化业务洞察的视觉表现。Seaborn:Seaborn是另一个数据可视化库(在视觉上优于matplotlib),构建在matplotlib之上。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv('placement.csv')
print(df.head())
通过Pandas的read_csv函数,读取了placement数据集(与之前的文章中所做的相同)。在这里,placement是目标列,而CGPA和placement_exam_marks是特征列。
plt.figure(figsize=(16,5))
plt.subplot(1,2,1)
sns.histplot(df['cgpa'], kde=True)
plt.subplot(1,2,2)
sns.histplot(df['placement_exam_marks'], kde=True)
plt.show()
从上面的图中,可以看到placement marks列是右偏(正偏),因此,在本文的剩余部分,将仅在此列上进行异常值检测和分析。
df['placement_exam_marks'].describe()
使用describe函数对选定的特征进行分析,得到了以下洞察:25%分位数是17,50%分位数(中位数)是33,75%分位数是44。标准差是19.13,最小值是0,最大值是100。
sns.boxplot(data = df['placement_exam_marks'])
使用boxplot来检查是否有异常值在具有偏斜分布的列中,以便可以使用IQR通用方法来移除/处理它们。从图表/图中,可以看到在上区域有异常值,但没有下区域的异常值(将在下面进一步证明这一点)。
找到IQR
percentile25 = df['placement_exam_marks'].quantile(0.25)
percentile75 = df['placement_exam_marks'].quantile(0.75)
IQR = (75th quartile/percentile – 25th quartile/percentile)。因此,从上述两行代码中,首先使用预定义的quantile函数计算75th和25th四分位数。
print("75th quartile: ",percentile75)
print("25th quartile: ",percentile25)
75th四分位数是44,即44分的候选人仅落后25%。同样,对于25th四分位数,有17分,即17分的候选人领先25%。
iqr = percentile75 - percentile25
print ("IQR: ",iqr)
如上所述,计算IQR需要75th和25th四分位数,其中IQR是75th和25th四分位数之间的差值。
为什么需要IQR?答案很简单 - 为了计算上限和下限,需要IQR,因为它是公式的一部分。得到的值是27。
upper_limit = percentile75 + 1.5 * iqr
lower_limit = percentile25 - 1.5 * iqr
print("Upper limit",upper_limit)
print("Lower limit",lower_limit)
计算数据点的上限公式是75th百分位数 + 1.5 * 四分位距,同样,下限公式是25th百分位数 – 1.5 * IQR。在讨论boxplot时,看到下区域没有异常值,这里也可以看到,下限对应一个负值。
找出异常值
df[df['placement_exam_marks'] > upper_limit]
df[df['placement_exam_marks'] > upper_limit].count()
首先,返回了异常值的行;然后,借助count函数,了解到总行数是15。
修剪
new_df = df[df['placement_exam_marks'] < upper_limit]
new_df.shape
修剪是可以正确意义上移除异常值的第一种方式,因为不会给它们其他特定值或以其他方式处理它们。修剪从数据集中移除所有不良数据,以确保数据量不是太多;否则,对于分析,将没有足够的数据用于ML模型开发。
比较
plt.figure(figsize=(16,8))
plt.subplot(2,2,1)
sns.histplot(df['placement_exam_marks'], kde=True)
plt.subplot(2,2,2)
sns.boxplot(data = df['placement_exam_marks'])
plt.subplot(2,2,3)
sns.histplot(new_df['placement_exam_marks'], kde=True)
plt.subplot(2,2,4)
sns.boxplot(data = new_df['placement_exam_marks'])
plt.show()
现在是一些视觉比较的时候,可以看到在第3和第4个图中,分布图中60-80段的数据有轻微的峰值,与修剪前的图表相比。让知道是否移除了异常值的主要图表是boxplot。在图中,当比较时,肉眼可以看到几乎99%的异常值被移除了。
封顶
new_df_cap = df.copy()
new_df_cap['placement_exam_marks'] = np.where(
new_df_cap['placement_exam_marks'] > upper_limit,
upper_limit,
np.where(
new_df_cap['placement_exam_marks'] < lower_limit,
lower_limit,
new_df_cap['placement_exam_marks']
)
)
首先,做了一件事,就是有一个原始数据集的副本,这样也可以用于其他分析。然后使用np.where()将上限和下限值填充到异常值的两个区域,正如代码中所注意到的。
new_df_cap.shape