讯飞-用户新增预测挑战赛01

二分类问题和混淆矩阵

  1. 二分类问题
    二分类问题是一种分类问题,涉及将输入样本分为两个类别中的一个。例如,判断一封电子邮件是否为垃圾邮件(垃圾或非垃圾)、诊断患者是否患有某种疾病(患病或未患病)等。
  2. 混淆矩阵
    混淆矩阵是一种展示分类模型性能的表格。在二分类问题中,混淆矩阵由四个项组成:真正类(True Positive,TP)、真负类(True Negative,TN)、假正类(False Positive,FP)和假负类(False Negative,FN)。这些项表示以下内容:
    • TP:实际为正类且被预测为正类的数量。
    • TN:实际为负类且被预测为负类的数量。
    • FP:实际为负类但被预测为正类的数量(误报)。
    • FN:实际为正类但被预测为负类的数量(漏报)。
  1. Precision(精确率)
    精确率是预测为正类的样本中实际为正类的比例。计算公式为:Precision = TP / (TP + FP)。精确率衡量了模型的预测准确性,即在所有预测为正类的样本中,有多少样本实际上是正类。
  2. Recall(召回率)
    召回率是实际为正类的样本中被正确预测为正类的比例。计算公式为:Recall = TP / (TP + FN)。召回率也称为灵敏度或真阳性率,它衡量了模型对于实际正类样本的识别能力。

总结:

  • 混淆矩阵提供了更详细的分类模型性能信息,可以从 TP、TN、FP 和 FN 的角度了解模型的表现。
  • Precision 衡量了模型的预测准确性,即在预测为正类的样本中,有多少是真正的正类。
  • Recall 衡量了模型对实际正类样本的识别能力,即有多少实际正类被正确预测为正类。

在二分类问题中,根据任务的不同,可能会更关注 Precision 或 Recall,或在两者之间进行权衡。


解题思路

  • 问题分析
  • 数据探索:数据类型的不同。
  • 数据清洗:缺失/离群的数据,NaN,空值...(异常值)剔除
  • 特征工程:寻求办法将冗余数据剔除掉,将有用的数据加以深化
  • 模型训练:函数(输入+输出->模型的预测值->f1_score验证->改进输入数据/模型)
  • 得到结果

baseline和f1_score

  • Baseline(基准线):基准线是一个参考点,用于比较和评估模型的性能。通常情况下,基准线是一种简单、常见或者随机的方法,作为比较模型效果的标准。当开发一个新的模型时,比较模型的表现与基准线可以帮助判断模型是否真正有效。如果模型的性能不能超过基准线,那么这个模型可能不具有实际应用价值。
  • F1-score:F1-score 是一个综合考虑 Precision(精确率)和 Recall(召回率)的度量指标,用于衡量二分类模型的性能。F1-score 是 Precision 和 Recall 的调和平均值,公式为:F1-score = 2 (Precision Recall) / (Precision + Recall)。F1-score 的取值范围在 0 到 1 之间,值越高表示模型的性能越好。F1-score 在数据不平衡或模型需在 Precision 和 Recall 之间权衡时特别有用,因为它能综合考虑两者。

代码

baseline
# 1. 导入需要用到的相关库
# 导入 pandas 库,用于数据处理和分析
import pandas as pd
# 导入 numpy 库,用于科学计算和多维数组操作
import numpy as np
# 从 sklearn.tree 模块中导入 DecisionTreeClassifier 类
# DecisionTreeClassifier 用于构建决策树分类模型
from sklearn.tree import DecisionTreeClassifier


# 2. 读取训练集和测试集
# 使用 read_csv() 函数从文件中读取训练集数据,文件名为 'train.csv'
train_data = pd.read_csv('用户新增预测挑战赛公开数据/train.csv')
# 使用 read_csv() 函数从文件中读取测试集数据,文件名为 'test.csv'
test_data = pd.read_csv('用户新增预测挑战赛公开数据/test.csv')


# 3. 将 'udmap' 列进行 One-Hot 编码 
# 数据样例:
#                    udmap  key1  key2  key3  key4  key5  key6  key7  key8  key9
# 0           {'key1': 2}     2     0     0     0     0     0     0     0     0
# 1           {'key2': 1}     0     1     0     0     0     0     0     0     0
# 2  {'key1': 3, 'key2': 2}   3     2     0     0     0     0     0     0     0

# 在 python 中, 形如 {'key1': 3, 'key2': 2} 格式的为字典类型对象, 通过key-value键值对的方式存储
# 而在本数据集中, udmap实际是以字符的形式存储, 所以处理时需要先用eval 函数将'udmap' 解析为字典

# 具体实现代码:
# 定义函数 udmap_onethot,用于将 'udmap' 列进行 One-Hot 编码
def udmap_onethot(d):
    v = np.zeros(9)  # 创建一个长度为 9 的零数组
    if d == 'unknown':  # 如果 'udmap' 的值是 'unknown'
        return v  # 返回零数组
    d = eval(d)  # 将 'udmap' 的值解析为一个字典
    for i in range(1, 10):  # 遍历 'key1' 到 'key9', 注意, 这里不包括10本身
        if 'key' + str(i) in d:  # 如果当前键存在于字典中
            v[i-1] = d['key' + str(i)]  # 将字典中的值存储在对应的索引位置上
            
    return v  # 返回 One-Hot 编码后的数组

# 注: 对于不理解的步骤, 可以逐行 print 内容查看
# 使用 apply() 方法将 udmap_onethot 函数应用于每个样本的 'udmap' 列
# np.vstack() 用于将结果堆叠成一个数组
train_udmap_df = pd.DataFrame(np.vstack(train_data['udmap'].apply(udmap_onethot)))
test_udmap_df = pd.DataFrame(np.vstack(test_data['udmap'].apply(udmap_onethot)))
# 为新的特征 DataFrame 命名列名
train_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
test_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
# 将编码后的 udmap 特征与原始数据进行拼接,沿着列方向拼接
train_data = pd.concat([train_data, train_udmap_df], axis=1)
test_data = pd.concat([test_data, test_udmap_df], axis=1)


# 4. 编码 udmap 是否为空
# 使用比较运算符将每个样本的 'udmap' 列与字符串 'unknown' 进行比较,返回一个布尔值的 Series
# 使用 astype(int) 将布尔值转换为整数(0 或 1),以便进行后续的数值计算和分析
train_data['udmap_isunknown'] = (train_data['udmap'] == 'unknown').astype(int)
test_data['udmap_isunknown'] = (test_data['udmap'] == 'unknown').astype(int)


# 5. 提取 eid 的频次特征
# 使用 map() 方法将每个样本的 eid 映射到训练数据中 eid 的频次计数
# train_data['eid'].value_counts() 返回每个 eid 出现的频次计数
train_data['eid_freq'] = train_data['eid'].map(train_data['eid'].value_counts())
test_data['eid_freq'] = test_data['eid'].map(train_data['eid'].value_counts())


# 6. 提取 eid 的标签特征
# 使用 groupby() 方法按照 eid 进行分组,然后计算每个 eid 分组的目标值均值
# train_data.groupby('eid')['target'].mean() 返回每个 eid 分组的目标值均值
train_data['eid_mean'] = train_data['eid'].map(train_data.groupby('eid')['target'].mean())
test_data['eid_mean'] = test_data['eid'].map(train_data.groupby('eid')['target'].mean())


# 7. 提取时间戳
# 使用 pd.to_datetime() 函数将时间戳列转换为 datetime 类型
# 样例:1678932546000->2023-03-15 15:14:16
# 注: 需要注意时间戳的长度, 如果是13位则unit 为 毫秒, 如果是10位则为 秒, 这是转时间戳时容易踩的坑
# 具体实现代码:
train_data['common_ts'] = pd.to_datetime(train_data['common_ts'], unit='ms')
test_data['common_ts'] = pd.to_datetime(test_data['common_ts'], unit='ms')

# 使用 dt.hour 属性从 datetime 列中提取小时信息,并将提取的小时信息存储在新的列 'common_ts_hour'
train_data['common_ts_hour'] = train_data['common_ts'].dt.hour
test_data['common_ts_hour'] = test_data['common_ts'].dt.hour


# 8. 加载决策树模型进行训练(直接使用sklearn中导入的包进行模型建立)
clf = DecisionTreeClassifier()
# 使用 fit 方法训练模型
# train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1) 从训练数据集中移除列 'udmap', 'common_ts', 'uuid', 'target'
# 这些列可能是特征或标签,取决于数据集的设置
# train_data['target'] 是训练数据集中的标签列,它包含了每个样本的目标值
clf.fit(
    train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1),  # 特征数据:移除指定的列作为特征
    train_data['target']  # 目标数据:将 'target' 列作为模型的目标进行训练
)

# 9. 对测试集进行预测,并保存结果到result_df中
# 创建一个DataFrame来存储预测结果,其中包括两列:'uuid' 和 'target'
# 'uuid' 列来自测试数据集中的 'uuid' 列,'target' 列将用来存储模型的预测结果
result_df = pd.DataFrame({
    'uuid': test_data['uuid'],  # 使用测试数据集中的 'uuid' 列作为 'uuid' 列的值
    'target': clf.predict(test_data.drop(['udmap', 'common_ts', 'uuid'], axis=1))  # 使用模型 clf 对测试数据集进行预测,并将预测结果存储在 'target' 列中
})


# 10. 保存结果文件到本地
# 将结果DataFrame保存为一个CSV文件,文件名为 'submit.csv'
# 参数 index=None 表示不将DataFrame的索引写入文件中
result_df.to_csv('submit.csv', index=None)
自己的改进代码
import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifier

# 读取数据集
train_data = pd.read_csv('用户新增预测挑战赛公开数据/train.csv')
test_data = pd.read_csv('用户新增预测挑战赛公开数据/test.csv')

# One-Hot 编码 udmap 列
def udmap_onethot(d):
    v = np.zeros(9)
    if d == 'unknown':
        return v
    d = eval(d)
    for i in range(1, 10):
        key = 'key' + str(i)
        if key in d:
            v[i-1] = d[key]
    return v

train_udmap_df = pd.DataFrame(np.vstack(train_data['udmap'].apply(udmap_onethot)))
test_udmap_df = pd.DataFrame(np.vstack(test_data['udmap'].apply(udmap_onethot)))
train_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
test_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]

train_data = pd.concat([train_data, train_udmap_df], axis=1)
test_data = pd.concat([test_data, test_udmap_df], axis=1)

# 编码 udmap 是否为空
train_data['udmap_isunknown'] = (train_data['udmap'] == 'unknown').astype(int)
test_data['udmap_isunknown'] = (test_data['udmap'] == 'unknown').astype(int)

# 提取 eid 的频次特征
eid_freq_mapping = train_data['eid'].value_counts()
train_data['eid_freq'] = train_data['eid'].map(eid_freq_mapping)
test_data['eid_freq'] = test_data['eid'].map(eid_freq_mapping)

# 提取 eid 的标签特征
eid_mean_mapping = train_data.groupby('eid')['target'].mean()
train_data['eid_mean'] = train_data['eid'].map(eid_mean_mapping)
test_data['eid_mean'] = test_data['eid'].map(eid_mean_mapping)

# 提取时间戳
train_data['common_ts'] = pd.to_datetime(train_data['common_ts'], unit='ms')
test_data['common_ts'] = pd.to_datetime(test_data['common_ts'], unit='ms')
train_data['common_ts_hour'] = train_data['common_ts'].dt.hour
test_data['common_ts_hour'] = test_data['common_ts'].dt.hour

# 训练决策树模型
clf = DecisionTreeClassifier()
features = train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1)
target = train_data['target']
clf.fit(features, target)

# 预测测试集并保存结果
test_features = test_data.drop(['udmap', 'common_ts', 'uuid'], axis=1)
result_df = pd.DataFrame({
    'uuid': test_data['uuid'],
    'target': clf.predict(test_features)
})

# 保存结果文件到本地
result_df.to_csv('submit.csv', index=None)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值