24.11.5 kaggle入门DAY1-Elo信用度预测-B站九天老师

167 阅读17分钟

kaggle 账号注册

kaggle 界面

kaggle 赛事页面

image.png

Data 数据

数据下载

方式一:kaggle 命令行(推荐)

1.首先要安装 kaggle 包 pip install kaggle --user

2.找到页面中命令行部分

方式二:Download 压缩包

image.png

kaggle 命令行 下载数据集遇到的问题:

OSError: Could not find kaggle.json. Make sure it's located in C:\Users\xxxxx.kaggle. Or use the environment method. See setup instructions at github.com/Kaggle/kagg…

image.png 解决方案 kaggle 首页右上角点击头像

  • 进入 Settings下滑找到 API
  • 点击 Create New API Token,系统会自动下载一个 kaggle.json 文件。
  • kaggle.json 文件放在 C:\Users\Mryang.kaggle 目录中(如果没有 .kaggle 文件夹,请手动创建)。

拿到数据集后的工作

  • 了解每个数据集的含义

1.赛题背景简介

在了解Kaggle的基本功能布局后,接下来我们来简单查看赛题的基本介绍。当然,此处的简单也并非主动有意为之,而是在官方给出的说明中,其实并没有太多有效的业务信息。我们可以先从上述Overview的内容入手进行了解:

巴西支付品牌Elo

本次竞赛其实是由巴西最大的支付品牌之一的Elo和Kaggle合作举办的比赛,奖金和数据都由Elo公司提供。谈到支付品牌,国内用户首先会想到类似支付宝、ayPal这些带有浓烈互联网色彩的支付品牌,但是在巴西,线上支付更多是由本地银行主导,且线上支付的信贷产品也主要以信用卡为主。Elo就是这样的一家公司,在2011年由巴西三家主要银行合资创立,主要负责线上支付业务,并且以信用卡作为核心金融产品,目前已发放超过1.1亿张信用卡,是巴西最大的本地在线支付品牌之一。并且,Elo不仅是支付入口,更是一个”o2o“平台,通过App,用户可以查阅本地餐饮旅馆电影旅游机票等各项服务,并支持信用卡在线支付。形象点理解,就好比把美团主页移到支付宝,并且支付宝没有花呗,取而代之的是自己发行的信用卡。或者更加形象的理解就类似国内招行信用卡掌上生活的业务模式.

业务目标:更好的进行本地服务推荐

在官方给出的说明中,我们不难发现,Elo使用机器学习算法技术的核心目的,是为了更好的在App内为用户推荐当地吃穿住行的商家服务,包括热门餐厅展示、优惠折扣提醒等(非常类似上图掌上生活首页的推荐)。也就是说,其根本目的是为了推荐,或者说为每个用户进行更加个性化的推荐,也就是赛题标题中的所写的:Merchant Category Recommendation(商户类别推荐)。但是,需要注意的是,本次竞赛的建模目标却和推荐系统并不直接相关。赛题说明中,在介绍完业务目标之后,紧接着就介绍了本次赛题的目标:对用户的忠诚度评分进行预测

算法目标:用户忠诚度评分预测

所谓用户忠诚度评分,通过后续查看Evaluation不难发现,其实就是对每个用户的评分进行预测,本质上是个回归问题。 相信刚接触到本次赛题的小伙伴,一定会觉得赛题说明和建模目标有些“文不对题”,毕竟用户忠诚度评分貌似和个性化推荐并无直接关系,尤其此处用户忠诚度评分并不是针对某类商品或者某类商家的忠诚度评分。

围绕这个问题,赛题说明给出了非常笼统的解释,只是简单说到通过对用户忠诚度评分,能够为其提供最相关的机会(servethe mostrelevant opportunities toindividuals),或者可以理解成是用户较为中意的线下服务,并且帮助ELo节省活动成本,为用户提供更好的体验。其实也就等于是没有解释忠诚度评分和推荐系统到底是什么关系。Kaggle本赛题论坛上也有很多相关讨论帖,官方给出的解释大意是通过忠诚度评分给用户推荐商铺和商品,这个过程并不是一个传统的协同过滤或者推荐系统进行推荐的过程,无论如何,先做好忠诚度预测就好。

借助论坛挖掘更多信息

当然,如果你有类似疑问,那么一定也是很多竟赛小伙伴的疑问,并且很多问题肯定在论坛上有非常热烈的讨论。因此无论是在赛题理解,还是实际建过程中,遇到问题第一时间还是应该回到Kaggle论坛上来查阅资料或者参与讨论。关于忠诚度评分如何能够解决精准推荐的问题问题,本次竟赛的榜一大佬给出了自己的理解:www.kaggle.com/c/elo-merch… 。此外,在论坛置顶中贴中的部分评论也值得一看,www.kaggle.com/c/elo-merch…:

(1)对于Elo来说,其实是有一套计算用户忠诚度的公式的,这也就是标签的由来。因此我们在进行建模的时候实际上是为了建立一套计算过程,尽可能逼近这个公式的计算结果;

(2)但是,通过简单尝试不难发现,Elo内部计算忠诚度的公式极有可能完全不是我们现在看到的这些字段,也就是说我们需要使用另一套字段去尽可能还原Elo内部计算忠诚度的过程;

(3)忠诚度评分如何影响精准推荐,这个过程极有可能类似游戏匹配机制,即不同分数段、不同战绩有可能匹配到不同的对手,而本次竞赛中其实只有关于用户一方分数的计算。

至此,我们就完成了赛题背景所有关键信息的分析与挖掘。一定程度挖掘赛题业务背景将有助于辅助后续建模工作的展开,根据目前所掌握的信息,可能需要用到用户画像中的用户价值分层方法来辅助进行特征工程,类似RFM模型中的关键指标。当然,更多信息大家也可以参考论坛中其他帖子。不过值得一提的是,算法竞赛中对于赛题背景的业务挖掘点到即止即可,一方面是因为出于保密性要求,竞赛主办方会刻意隐藏部分信息,脱创造新字段、甚至是不给出字段解释都是常见方法;另一方面,对于机器学习来说敏、创造新字段、甚至是不给出字段解释都是常见方法;另一方面,对于机器学习来说重数字规律可能会强于重业务逻辑。 image.png

二、train和test解读与初步探索

1. train 和 test 数据集解读

首先先进行数据读取。当然考虑到后续数据集规模较大,我们可以提前导入 gc 包以进行内存管理。在实际清理内存时,我们可以先使用 del 删除对象、再使用gc.collect(0),以达到手动清理内存的目的。

gc 包小知识 在 Python 中,gc 指的是垃圾回收(Garbage Collection)模块,它是 Python 标准库的一部分。这个模块提供了接口来控制垃圾回收器的操作,可以用来管理内存中的对象回收。

主要功能

gc 模块主要提供以下几个功能:

  • 启用和禁用垃圾回收:默认情况下,垃圾回收器是开启的,但你可以通过 gc.disable() 禁用它,或用 gc.enable() 重新启用它。
  • 手动触发垃圾回收:可以使用 gc.collect() 手动触发垃圾回收,这在某些内存敏感的场景或长时间运行的任务中特别有用。
  • 获取垃圾回收器信息gc 模块可以提供关于垃圾回收器状态和收集的不可达(即悬浮垃圾)对象的信息。

使用场景

  • 处理大量数据:在处理大型数据集或执行内存密集型操作时,及时清理不再使用的内存可以避免占用过多系统资源。
  • 优化性能:在某些情况下,频繁的自动垃圾回收可能会影响程序性能。在这些情况下,你可能想要控制何时进行垃圾回收,以优化程序的运行效率。
  • 资源清理:在使用了大量资源或复杂引用的情况下,确保这些资源被及时释放,特别是在资源受限的环境中。

以下代码都在 jupyter notebook 中运行 pycharm编辑器终端(要运行的项目):

jupyter notebook

弹出浏览器网页

import gc
import pandas as pd
train = pd.read_csv('./kaggle/1.elo-merchant-category-recommendation/train.csv')
test = pd.read_csv('./kaggle/1.elo-merchant-category-recommendation/test.csv')

image.png

# 查看数据集规模
(train.shape, test.shape)

image.png

train.head(5)

image.png

# 查看数据集信息
train.info()

image.png

解析

当前的数据集包含 201,917 条记录和 6 列,详细信息如下:

  • first_active_month: 201,917 个非空值,数据类型为 object(字符串),表示某个卡片首次激活的月份。
  • card_id: 201,917 个非空值,数据类型为 object,每张卡片的唯一标识符。
  • feature_1, feature_2, feature_3: 这些是整数类型 (int64) 的特征列,每列包含 201,917 个非空值。
  • target: 目标变量,数据类型为 float64,同样包含 201,917 个非空值。
  • 数据总共占用约 9.2 MB 内存。

tips:问题一:除了第一个“first_active_month”和“card_id”,其他都不知道是什么特征。这个怎么解决?

  • 读取 Data_Dictionary 回顾数据字典中的train表,查看train数据集中各字段解释:
pd.read_excel('./kaggle/1.elo-merchant-category-recommendation/Data_Dictionary.xlsx', header=2, sheet_name='train')

image.png

image.png

  • test:测试数据集
# 查看前5条数据,和submission一致
test.head(5)

image.png

test.info()

image.png

解析

你的数据集包含 123,623 条记录和 5 列,具体信息如下:

  • first_active_month: 数据类型为 object(字符串),包含 123,622 个非空值,表示卡片首次激活的月份。
  • card_id: 数据类型为 object,包含 123,623 个非空值,卡片的唯一标识符。
  • feature_1, feature_2, feature_3: 整数类型 (int64) 的特征列,每列包含 123,623 个非空值。

并且各字段的解释和train一致。实际比赛过程中,由于测试集的标签“不可知”,所以需要在训练集train上划分出验证集来进行模型泛化能力评估。

2.数据质量分析

在实际建模过程中,首先我们会先校验数据的正确性,并检验接下来简单数据探索。缺失值、异常值等情况。

数据正确性校验

所谓数据正确性,指的是数据本身是否符合基本逻辑,例如此处信用卡id作为建模分析对象独一无二的标识,我们需要验证其是否确实独一无二,并且训练集和测试集信用卡id无重复。

# 检测训练集id无重复
train['card_id'].nunique() == train.shape[0]

image.png

# 检测测试集id无重复
test['card_id'].nunique() == test.shape[0]

image.png

# 检验训练集和测试集id都是唯一值
test['card_id'].nunique() + train['card_id'].nunique() == len(set(test['card_id']))+ len(set(train['card_id']))

image.png

检验数据缺失情况
# 按列求缺失值并汇总
train.isnull().sum()

image.png

test.isnull().sum()

image.png 能够发现数据集基本无缺失值,测试集中的缺失值我们可以通过多种方式来进行填补,整体来说一条缺失值并不会对整体建模造成太大影响。

异常值

  接下来进行异常值检验。由于我们尚未对数据集特征进行预处理,因此我们先查看标签列的异常值情况。首先我们可以用describe()方法查看这一列的基本统计信息:

在 Python 的 Pandas 库中,describe() 函数是一个非常有用的工具,用于快速生成数据的统计摘要。这个方法主要应用于数据探索和初步分析,它提供了数据集中数值型和类别型列的概览。

功能

数值数据:对于数值型列,describe() 默认返回描述性统计数据,包括:

  • count:非空值的数量
  • mean:平均值
  • std:标准差
  • min:最小值
  • 25% :第一四分位数
  • 50% (median):中位数
  • 75% :第三四分位数
  • max:最大值

对象或类别数据:对于类别型或文本数据,describe() 返回:

  • count:非空值的数量
  • unique:唯一值的数量
  • top:出现频率最高的值
  • freq:最高频率值的出现次数

image.png

由于该列是连续变量,我们可以借助概率密度直方图进行分布的观察:

import seaborn as sns
import matplotlib.pyplot as plt

image.png

# 概率密度直方图
sns.set()
sns.histplot(train['target'], kde=True)

image.png 能够发现,大部分用户忠诚度评分都集中在[-10,10]之间,并且基本符合正态分布,唯一需要注意的是有个别异常值取值在-30以下,该数据在后续分析中需要额外注意。我们可以简单查看有多少用户的标签数值是小于30的当然,对于连续变量,一般可以采用3α原则进行异常值识别,此处我们也可以简单计算下异常值范围:

(train['target']<-30).sum()

image.png 约占整体20万数据的1%。

当然,对于连续变量,一般可以采用3𝛿3δ原则进行异常值识别,此处我们也可以简单计算下异常值范围:

statistics.loc['mean'] - 3 * statistics.loc['std']

image.png

异常值分析

需要注意的是,此处我们是围绕标签进行的异常值检测,而本案例中标签并不是自然数值测量或统计的结果(如消费金额、身高体重等),而是通过某种公式人工计算得出(详见赛题分析)。出现如此离群点极有可能是某类特殊用户的标记。因此不宜进行异常值处理,而应该将其单独视作特殊的一类,在后续建模分析时候单独对此类用户进行特征提取与建模分析。

4.规律一致性分析

接下来,进行训练集和测试集的规律一致性分析。

所谓规律一致性,指的是需要对训练集和测试集特征数据的分布进行简单比对,以“确定”两组数据是否诞生于同一个总体,即两组数据是否都遵循着背后总体的规律,即两组数据是否存在着规律一致性。

我们知道,尽管机器学习并不强调样本-总体的概念,但在训练集上挖掘到的规律要在测试集上起到预测效果,就必须要求这两部分数据受到相同规律的影响。一般来说,对于标签未知的测试集,我们可以通过特征的分布规律来判断两组数据是否取自同一总体。

单变量分析

首先我们先进行简单的单变量分布规律的对比。由于数据集中四个变量都是离散型变量,因此其分布规律我们可以通过相对占比分布(某种意义上来说也就是概率分布)来进行比较。

例如首先我们查看首次激活月份的相对占比分布可以通过如下代码实现:

# 特征列名
features = ['first_active_month','feature_1','feature_2','feature_3']

# 训练集/测试集样本总数
train_count = train.shape[0]
test_count = test.shape[0]

image.png

# 不同取值水平汇总后排序再除以样本总数
train['first_active_month'].value_counts().sort_index()/train_count

image.png

# 分布图如下所示:
(train['first_active_month'].value_counts().sort_index()/train_count).plot()

image.png 同时对比训练集和测试集的四个特征,可以通过如下代码实现:

for feature in features:
    (train[feature].value_counts().sort_index()/train_count).plot()
    (test[feature].value_counts().sort_index()/test_count).plot()
    plt.legend(['train''test'])
    plt.xlabel(feature)
    plt.ylabel('ratio')
    plt.show()

image.png

image.png

image.png

image.png image.png 能够发现,两组数据的单变量分布基本一致。

多变量联合分布

接下来,我们进一步查看联合变量分布。所谓联合概率分布,指的是将离散变量两两组合,然后查看这个新变量的相对占比分布。例如特征1有0/1两个取值水平,特征2有A/B两个取值水平,则联合分布中就将存在0A、0B、1A、1B四种不同取值水平,然后进一步查看这四种不同取值水平出现的分布情况。

首先我们可以创建如下函数以实现两个变量“联合”的目的:

def combine_feature(df):
    cols = df.columns
    feature1 = df[cols[0]].astype(str).values.tolist()
    feature2 = df[cols[1]].astype(str).values.tolist()
    return pd.Series([feature1[i]+ '&' + feature2[i] for i in range(df.shape[0])])

image.png

简单测试函数效果:

# 选取两个特征
cols = [features[0],features[1]]
cols

image.png

#查看合并后结果
train_com = combine_feature(train[cols])
train_com

image.png

进一步计算占比分布:

train_dis=train_com.value_counts().sort_index()/train_count
train_dis

image.png

当然,也可以对测试集进行相同操作:

test_dis=combine_feature(test[cols]).value_counts().sort_index()/test_count
test_dis

有问题!!!!!

image.png

然后对比二者分布:

# 创建新的 index
index_dis = pd.Series(train_dis.index.tolist() + test_dis.index.tolist()).drop_duplicates()

# 对缺失值填补为0并绘制图表
(index_dis.map(train_dis).fillna(0)).plot()
#绘图
plt.legend(['train','test'])
plt.xlabel('&'.join(cols))
plt.ylabel('ratio')
plt.show()

image.png

image.png

能够发现其分布基本一致。当然我们可以通过如下代码快速致性所有两两变量联合分布的 比较:

n = len(features)
for i in range(n - 1):
    for j in range(i + 1, n):
        cols = [features[i], features[j]]
        print(cols)
        
        # 计算训练集和测试集的分布
        train_dis = combine_feature(train[cols]).value_counts().sort_index() / train_count
        test_dis = combine_feature(test[cols]).value_counts().sort_index() / test_count
        
        # 创建新的 index
        index_dis = pd.Series(train_dis.index.tolist() + test_dis.index.tolist()).drop_duplicates()
        
        # 绘制图表
        (index_dis.map(train_dis).fillna(0)).plot()
        (index_dis.map(test_dis).fillna(0)).plot()
        
        # 图表设置
        plt.legend(['train', 'test'])
        plt.xlabel('&'.join(cols))
        plt.ylabel('ratio')
        plt.show()

image.png

image.png

image.png

image.png

image.png

image.png

能够发现所有联合变量的占比分布基本一致。数据集整体质量较高,且基本可以确认,训 练集和测试集取自同一样本总体。

规律一致性分析的实际作用

在实际建模过程中,规律一致性分析是非常重要但又经常容易被忽视的一个环节。通过规律一致性分析,我们可以得出非常多的可用于后续指导后续建模的关键性意见。通常我们可以根据规律一致性分析得出以下基本结论:

(1)如果分布非常一致,则说明所有特征均取自同一整体,训练集和测试集规律拥有较高一致性,模型效果上限较高,建模过程中应该更加依靠特征工程方法和模型建模技巧提高最终预测效果;

(2)如果分布不太一致,则说明训练集和测试集规律不太一致,此时模型预测效果上限会受此影响而被限制,并且模型大概率容易过拟合,在实际建模过程中可以多考虑使用交叉验证等方式防止过拟合,并且需要注重除了通用特征工程和建模方法外的trick的使用;

至此,我们就完成了核心数据集的数据探索,接下来,我们还将围绕其他的补充数据进行进一步的数据解读与数据清洗,并为最终的建模工作做好相关准备。