我们以2022年全国服务外包大赛的A03题目作为示例。
问题的主要任务时找出商品的销量异常和价格异常,提供4个月的商品信息数据,共1700万余条,4个月的店铺信息数据,共60万余条,强调时间复杂度空间复杂度、异常值识别率和准确率。我们用店铺分析辅助商品的异常,以提高可信度和准确率。
店铺部分数据链接:https://pan.baidu.com/s/1iAp-s2JwG_YTB35BevMNyQ 提取码:jhnb
但是由于数据分布多样,异常店铺往往和奢侈品店铺以及火爆店铺同时出现,大大降低了我们的准确率。因此我们拟采取如下几个办法解决:
思路:
这样就算部分异常值被归入奢侈品行列,依靠第三步类目索引也会回到大部分的本类店铺所在类别,然后在异常值识别时被识别出来。相当于在总流程中添加了这一步:
代码如下:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
pd.set_option('display.max_columns', None)
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.cluster import KMeans
def clustering(data):
col_sale_amount = ["SHOP_SALES_AMOUNT_x", "Rate_amount", "MAIN_BUSINESS"]
sc = StandardScaler().fit(data[col_sale_amount]) # 归一化
data[col_sale_amount] = sc.transform(data[col_sale_amount])
file_name = "shop_sale_amount_cluster"
SSE(data, col_sale_amount, file_name)
k_sale_volumn = 4
df_cluster_result = Kmeans(data, col_sale_amount, k_sale_volumn, file_name)
df_cluster_result[col_sale_amount] = sc.inverse_transform(df_cluster_result[col_sale_amount])
df_cluster_result = df_cluster_result.sort_values("index")
for i in range(k_sale_volumn):
df_cluster_result[df_cluster_result["volumn_cluster"] == i].to_csv(file_name + "/ cluster " + str(i) + ".csv", encoding="utf-8-sig")
return df_cluster_result
def SSE(data, col_name, file_name):
SSE = []
left = 2
right = 16
for k in range(left, right):
km = KMeans(n_clusters=k)
km.fit(data[col_name])
SSE.append(km.inertia_)
# 肘部法取k值
xx = range(left, right)
plt.xlabel("k")
plt.ylabel("SSE")
plt.plot(xx, SSE, "o-")
plt.savefig(file_name + "\SSE " + ".png")
# plt.show()
plt.clf() # 清图
def Kmeans(data, col, k, file_name):
km = KMeans(n_clusters=k, random_state=1129).fit(data[col])
# print(km.labels_)
data["volumn_cluster"] = km.labels_
data = data.sort_values(by="volumn_cluster")
plt.rcParams["font.size"] = 14
colors = np.array(["lightcoral", "pink", "lightsteelblue", "lightseagreen", "grey", "green", "yellow"])
# masks = np.array([">", "x", "8", "*"])
ele_x = col[0]
ele_y = col[1]
xx = np.array(data[ele_x])
yy = np.array(data[ele_y])
cc = np.array(data["volumn_cluster"])
plt.scatter(xx, yy, c=colors[cc], s=2) # c=colors[cc]
plt.xlabel(ele_x)
plt.ylabel(ele_y)
plt.savefig(file_name+"\K_Means " + ".png")
plt.show()
return data
def main():
# 聚类
# df_filled_featured为待预测数据
df_filled_featured["MAIN_BUSINESS"] = df_filled_featured["MAIN_BUSINESS"].apply(lambda x: dict_MainBussiness[x])
df_filled_featured_clustered = clustering(df_filled_featured)
print("初步聚类完毕!!!")
# 异常值筛选,此处重点不在这里
wrong_in_price(df_filled_featured_clustered_boxed, mode="slow")
wrong_in_volumn(df_filled_featured_clustered_boxed, mode="slow")
if __name__ == '__main__':
main()
关于为什么采取K-Means聚类而不是其他的聚类方法:
- K-MEANS聚类的目的只是根据几个特定的指标将商品分为多个种类,利于后面的模型实施与调参;其本意并非寻找离群点。
- 异常值数量较少,对聚类中心影响有限。就算收到影响,大部分正常数据类别还是对的,所以我们根据主要业务索引回来,将被归错类的异常值放回本来属于它的聚类。
- DBscan和DeBaCL等基于密度聚类算法在初期建树过程中所需空间太大,最多就只能承受3w不到的数据,这对于我们60w+和1700w+的数据大小是非常不友好的。
聚类结果:
其中,聚类三四已经筛选出部分异常值变量了:
为了区别异常店铺和奢侈品店铺,一种办法是设计衍生变量,比如店铺商品均价与产业商品均价的均价的比值等等,从这个角度设计衍生变量可以很大程度上缓解奢侈品行业店铺在价格异常店铺以及廉价商品店铺在销量异常店铺中霸屏的现象。
计算方法其实就是pandas的熟练应用,在此不赘述,可以参考这篇博客:https://blog.csdn.net/Hjh1906008151/article/details/124330708
有点像上一个解决方法,其实就是找一个切入点。因为我们的目标是寻找销量异常和价格异常,这两种异常在很大程度上会导致销售额增多,因此我们可以考虑设置一个销售额异常作为初筛。这部分的思路的要点就是寻找两种异常的共性。
修改损失函数 如果这部分有用到神经网络等方法,个人认为可以采取这个办法。因为异常值的加入会导致神经网络在学习时学到不好的特征,要知道数据集数据有问题在神经网络训练中的后果是灾难性的,为了缓解这个问题,可以采用 Minkowski error平滑异常值带来的影响,效果如下:
优化损失函数之后:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)