Predict Podcast Listening Time-(回归+特征工程+xgb)

news2025/5/22 23:38:40

Predict Podcast Listening Time

题意:

给你每个播客的信息,让你预测观众的聆听时间。

数据处理:

1.构造新特征收听效率进行分组
2.对数据异常处理
3.对时间情绪等进行数值编码
4.求某特征值求多项式特征
5.生成特征组合
6.交叉验证并encoder编码

建立模型:

1.创建xgb训练回调函数,动态调整学习率
2.DMatrix优化数据,训练模型

代码:
import numpy as np
import pandas as pd
import os
import os
import warnings
import numpy as np
import pandas as pd
import xgboost as xgb
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import KFold
from sklearn.preprocessing import LabelEncoder
from cuml.preprocessing import TargetEncoder
from itertools import combinations
from tqdm.auto import tqdm

for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' #仅输出错误日志
warnings.simplefilter('ignore') #忽略警告日志
pd.options.mode.copy_on_write = True #数据仅存一份,其他是视图

# 探索性数据分析 (EDA)
def basic_eda(df, name="Dataset"):
    print(f"\n----- {name} EDA -----")
    print(df.shape)
    print(df.info())
    print(df.describe())
    print(df.isnull().sum().sort_values(ascending=False).head(10)) # 缺失值降序查看10个
    print(f"Duplicated rows: {df.duplicated().sum()}") # 查看重复行的个数

    #查看缺失值的热力图
    plt.figure(figsize=(10, 6)) #大小10×6
    sns.heatmap(df.isnull(), cbar=False, cmap="viridis") #绘制热力图
    plt.title(f'Missing Values Heatmap - {name}')
    plt.show()

    # df.isnull(): 输入布尔矩阵
    # cbar = False: 关闭颜色条
    # cmap = "viridis": 使用Viridis颜色映射(黄 - 绿 - 蓝渐变)
    # plt.title(...): 设置标题
    # plt.show(): 显示图像

    # 黄色区域表示缺失值
    # 深色区域表示无缺失值
    # 横向条纹:某列存在大量缺失值
    # 纵向条纹:某行存在多个缺失值

# 特征组合生成
def process_combinations_fast(df, columns_to_encode, pair_sizes, max_batch_size=2000):
    # columns_to_encode: 需要生成组合特征的列名列表
    # pair_sizes: 组合大小列表(如[2, 3]表示生成2列和3列的组合)
    # max_batch_size: 每批处理的最大组合数(默认2000,避免内存溢出)

    # 将指定列转换为字符串类型,为后续拼接操作做准备(字符串拼接更直观)。
    str_df = df[columns_to_encode].astype(str)
    # 创建LabelEncoder实例,用于将拼接后的字符串编码为数值。
    le = LabelEncoder()
    total_new_cols = 0

    # 遍历每个组合大小 r(如先处理所有2列组合,再处理3列组合)。
    for r in pair_sizes:
        print(f"\nProcessing {r}-combinations...")
        # 计算从 columns_to_encode 列中选取 r 列的组合总数。
        n_combinations = np.math.comb(len(columns_to_encode), r)
        print(f"Total {r}-combinations: {n_combinations}")

        # 使用itertools.combinations生成所有可能的列组合迭代器。
        combos_iter = combinations(columns_to_encode, r)

        # 初始化两个列表:
        # batch_cols: 存储当前批次的列组合(如[['A', 'B'], ['A', 'C']])
        # batch_names: 存储对应的新列名(如['A+B', 'A+C'])
        batch_cols, batch_names = [], []

        #创建进度条,总长度为组合总数 n_combinations。
        with tqdm(total=n_combinations) as pbar:

            # 进入无限循环,直到处理完所有组合。每次循环开始时清空批次列表。
            while True:
                batch_cols.clear()
                batch_names.clear()

                # 从迭代器中获取最多max_batch_size个组合:
                # next(combos_iter): 获取下一个组合(如('A', 'B'))
                # 转换为列表并添加到batch_cols
                # 生成新列名(如'A+B')并添加到batch_names
                # 迭代器耗尽时触发StopIteration,退出循环
                for _ in range(max_batch_size):
                    try:
                        cols = next(combos_iter)
                        batch_cols.append(list(cols))
                        batch_names.append('+'.join(cols))
                    except StopIteration:
                        break
                # 如果当前批次为空,说明所有组合已处理完毕,退出循环。
                if not batch_cols:
                    break

                # 遍历当前批次的所有组合:
                # 字符串拼接:将组合内的列值按行拼接(如'A_val' + 'B_val')
                # 标签编码:将拼接后的字符串转换为数值,并加1(避免0值)
                # 更新进度条:每处理一个组合,进度条前进1步
                for cols, new_name in zip(batch_cols, batch_names):
                    result = str_df[cols[0]].copy()
                    for col in cols[1:]:
                        result += str_df[col]
                    df[new_name] = le.fit_transform(result) + 1
                    pbar.update(1)

                # 累计当前批次生成的新列数。
                total_new_cols += len(batch_cols)

        #打印当前组合大小的处理结果及总列数。
        print(f"Completed {r}-combinations. Total columns now: {len(df.columns)}")

    return df

# 动态调整学习率,115轮次前0.05,之后0.01
def learning_rate_scheduler(epoch):
    return 0.05 if epoch < 115 else 0.01

# 数据预处理
df_train = pd.read_csv("/kaggle/input/playground-series-s5e4/train.csv")
df_test = pd.read_csv('/kaggle/input/playground-series-s5e4/test.csv')
df = pd.concat([df_train, df_test], axis=0, ignore_index=True)
df.drop(columns=['id'], inplace=True)
df = df.drop_duplicates()

# 新特征:收听效率 = 收听时长 / 节目时长
df1 = df.copy()
df1["Listening_Eff"] = df1["Listening_Time_minutes"] / df1["Episode_Length_minutes"]
genre = df1.groupby("Genre")["Listening_Eff"].mean().sort_values(ascending=False)
# 功能:按 Genre(流派)分组,计算每组的 Listening_Eff 均值,并按降序排列。
# 操作分解:
# 分组:df1.groupby("Genre") 将数据按流派划分。
# 列选择:["Listening_Eff"] 指定计算目标列为收听效率。
# 聚合:.mean() 计算每组的平均效率。
# 排序:.sort_values(ascending=False) 按效率值从高到低排序。
# 输出示例:
# Genre
# Comedy        0.82
# Drama         0.78
# Education     0.75
# ...
# Name: Listening_Eff, dtype: float64

print(genre)

# 展示关系图
plt.figure(figsize=(10, 6))
sns.barplot(x=genre.values, y=genre.index, palette="viridis")
plt.title("Average Listening Efficiency by Genre")
plt.xlabel("Listening_Time Eff")
plt.ylabel("Genre")
plt.show()

#进行eda查看
basic_eda(df, "Combined Dataset")

# 异常值处理
df['Episode_Length_minutes'] = np.clip(df['Episode_Length_minutes'], 0, 120) #节目时常限制在0-120
df['Host_Popularity_percentage'] = np.clip(df['Host_Popularity_percentage'], 20, 100) #将主持人热度百分比限制在[20, 100]
df['Guest_Popularity_percentage'] = np.clip(df['Guest_Popularity_percentage'], 0, 100) #将嘉宾热度百分比限制在 [0, 100]
df.loc[df['Number_of_Ads'] > 3, 'Number_of_Ads'] = 0 #将广告数量超过3个的节目标记为0

# 特征编码
# 自定义分类变量映射,然后应用映射
day_mapping = {'Monday':1, 'Tuesday':2, 'Wednesday':3, 'Thursday':4, 'Friday':5, 'Saturday':6, 'Sunday':7} #一周换为有序值
time_mapping = {'Morning':1, 'Afternoon':2, 'Evening':3, 'Night':4} #一天的时间换为有序数值
sentiment_mapping = {'Negative':1, 'Neutral':2, 'Positive':3} #将情感极性转换为有序数值

# 应用映射
df['Publication_Day'] = df['Publication_Day'].map(day_mapping)
df['Publication_Time'] = df['Publication_Time'].map(time_mapping)
df['Episode_Sentiment'] = df['Episode_Sentiment'].map(sentiment_mapping)

# 修正Episode_Title(移除"Episode "前缀并转为整数)
# 目标:从剧集标题中提取编号并转为整数
# 操作分解:
# 字符串替换:删除标题中的"Episode "前缀
# 类型转换:将结果转为整型(如"123"→123)
df['Episode_Title'] = df['Episode_Title'].str.replace('Episode ', '', regex=True).astype(int)

# 对剩余分类列进行标签编码
# 功能:创建Scikit-learn的LabelEncoder实例。
# 核心作用:将分类标签转换为0-based的整数编码(如['A','B','A']→[0,1,0])。
le = LabelEncoder()
for col in df.select_dtypes('object').columns: # 自动选择数据框中所有object类型的列(通常是字符串或混合类型列)。
    df[col] = le.fit_transform(df[col]) + 1

# 特征工程
# 多项式特征
for col in ['Episode_Length_minutes']:
    df[f"{col}_sqrt"] = np.sqrt(df[col]) # 平方根
    df[f"{col}_squared"] = df[col] ** 2 # 平方

# 分组均值编码(Target Encoding)
group_cols = ['Episode_Sentiment', 'Genre', 'Publication_Day', 'Podcast_Name', 'Episode_Title',
              'Guest_Popularity_percentage', 'Host_Popularity_percentage', 'Number_of_Ads']

# 使用tqdm库为循环添加进度条,提升大数据处理时的用户体验
for col in tqdm(group_cols, desc="Creating group mean features"):
    df[f"{col}_EP"] = df.groupby(col)['Episode_Length_minutes'].transform('mean')
# 分组:df.groupby(col) 按当前列分组(如按Genre分组)
# 聚合计算:['Episode_Length_minutes'].transform('mean') 计算每组的节目时长均值
# 特征映射:将均值结果广播回原始数据框的每一行
# 对齐机制:保证新列与原始数据框行索引完全一致
# 内存高效:相比apply方法,transform在大数据集上性能更优

# 生成组合特征
combo_columns = ['Episode_Length_minutes', 'Episode_Title', 'Publication_Time', 'Host_Popularity_percentage',
                 'Number_of_Ads', 'Episode_Sentiment', 'Publication_Day', 'Podcast_Name', 'Genre', 'Guest_Popularity_percentage']
df = process_combinations_fast(df, combo_columns, pair_sizes=[2, 3, 5, 7], max_batch_size=1000)

# 降低数据精度节省内存
df = df.astype('float32')

# 模型训练与预测
# 分割数据集
df_train = df.iloc[:-len(df_test)]
df_test = df.iloc[-len(df_test):].reset_index(drop=True)
df_train = df_train[df_train['Listening_Time_minutes'].notnull()]
target = df_train.pop('Listening_Time_minutes')
df_test = df_test.drop(columns=['Listening_Time_minutes'])

# 交叉验证设置
# n_splits=7:将数据划分为7个互斥的子集(folds)
# shuffle=True:划分前打乱数据顺序(防止数据固有顺序影响验证)
# random_state=seed:确保每次运行洗牌结果一致
seed = 42
cv = KFold(n_splits=7, random_state=seed, shuffle=True)
pred_test = np.zeros((250000,)) #创建形状为(250000,)的全零数组

params = {
    'objective': 'reg:squarederror',
    'eval_metric': 'rmse',
    'seed': seed,
    'max_depth': 19,
    'learning_rate': 0.03,
    'min_child_weight': 50,
    'reg_alpha': 5,
    'reg_lambda': 1,
    'subsample': 0.85,
    'colsample_bytree': 0.6,
    'colsample_bynode': 0.5,
    'device': "cuda"
}

# 功能:创建XGBoost训练回调函数,用于动态调整学习率
# LearningRateScheduler: XGBoost内置的回调类
# learning_rate_scheduler: 用户自定义的学习率计算函数
lr_callback = xgb.callback.LearningRateScheduler(learning_rate_scheduler)

# 交叉验证循环
for fold, (idx_train, idx_valid) in enumerate(cv.split(df_train)):
    print(f"\n--- Fold {fold + 1} ---")

    # 分割训练/验证集
    X_train, y_train = df_train.iloc[idx_train], target.iloc[idx_train]
    X_valid, y_valid = df_train.iloc[idx_valid], target.iloc[idx_valid]
    X_test = df_test[X_train.columns].copy()

    # 初始化编码器
    features = df_train.columns
    encoder = TargetEncoder(n_folds=5, seed=seed, stat="mean")

    # Apply Target Encoding
    for col in tqdm(features[:20], desc="Target Encoding first 20 features"): # 前20列单独处理
        # 拟合编码器(自动处理交叉验证)
        X_train[f"{col}_te1"] = encoder.fit_transform(X_train[[col]], y_train)
        # 验证集和测试集使用相同编码器
        X_valid[f"{col}_te1"] = encoder.transform(X_valid[[col]])
        X_test[f"{col}_te1"] = encoder.transform(X_test[[col]])

    for col in tqdm(features[20:], desc="Target Encoding remaining features"):
        # 拟合编码器(自动处理交叉验证)
        X_train[col] = encoder.fit_transform(X_train[[col]], y_train)
        # 验证集和测试集使用相同编码器
        X_valid[col] = encoder.transform(X_valid[[col]])
        X_test[col] = encoder.transform(X_test[[col]])

    # 创建DMatrix(XGBoost专用数据结构)
    # DMatrix是XGBoost定制的高性能数据结构,专为梯度提升算法优化
    dtrain = xgb.DMatrix(X_train, label=y_train)
    dval = xgb.DMatrix(X_valid, label=y_valid)
    dtest = xgb.DMatrix(X_test)

    # 训练模型(带早停和自定义学习率调度)
    model = xgb.train(
        params=params,
        dtrain=dtrain,
        num_boost_round=1_000_000,
        evals=[(dtrain, 'train'), (dval, 'validation')],
        early_stopping_rounds=30,
        verbose_eval=500,
        callbacks=[lr_callback]
    )

    # 预测并累积结果
    val_pred = model.predict(dval)
    pred_test += np.clip(model.predict(dtest), 0, 120) # 限制预测值范围
    print("-" * 70)

pred_test /= 7 # 平均7折结果

# 生成提交文件
df_sub = pd.read_csv("/kaggle/input/playground-series-s5e4/sample_submission.csv")
df_sub['Listening_Time_minutes'] = pred_test
df_sub.to_csv('submission.csv', index=False)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2383467.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis队列与Pub/Sub方案全解析:原理、对比与实战性能测试

一、为什么选择Redis实现消息队列&#xff1f; Redis凭借其内存级操作&#xff08;微秒级响应&#xff09;、丰富的数据结构以及持久化能力&#xff0c;成为构建高性能消息队列的热门选择。相比传统消息队列&#xff08;如Kafka/RabbitMQ&#xff09;&#xff0c;Redis在以下场…

OBOO鸥柏丨AI数字人触摸屏查询触控人脸识别语音交互一体机上市

OBOO鸥柏丨AI数字人触摸屏查询触控人脸识别语音交互一体机上市分析 OBOO鸥柏品牌推出的AI数字人触摸屏查询触控人脸识别语音交互一体机&#xff0c;是其在智能交互设备领域的又一创新产品。该一体机整合了触摸屏查询、AI人脸识别、AI声源定位语音麦克风&#xff0c;触控交互以…

第5天-python饼图绘制

一、基础饼图绘制(Matplotlib) 1. 环境准备 python 复制 下载 pip install matplotlib numpy 2. 基础饼图代码 python 复制 下载 import matplotlib.pyplot as plt# 数据准备 labels = [1, 2, 3, 4] sizes = [30, 25, 15, 30] # 各部分占比(总和建议100) colors…

2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛) 解题报告 | 珂学家

前言 题解 2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)。 vp了下&#xff0c;题目挺好的&#xff0c;难度也适中&#xff0c;但是彻底红温了。 第二题&#xff0c;题意不是那么清晰&#xff0c; M i n ( K 1 , K 2 ) Min(K_1, K_2) Min(K1​,K2​)容易求&#x…

LabVIEW风机状态实时监测

在当今电子设备高度集成化的时代&#xff0c;设备散热成为关键问题。许多大型设备机箱常采用多个风机协同散热&#xff0c;确保系统稳定运行。一旦风机出现故障&#xff0c;若不能及时察觉&#xff0c;可能导致设备损坏&#xff0c;造成巨大损失。为满足对机箱内风机状态实时监…

十一、面向对象底层逻辑-Dubbo过滤器Filter接口

一、引言&#xff1a;分布式系统中的可观测性与治理基石 在分布式服务调用链路中&#xff0c;如何在服务调用前后植入通用逻辑&#xff08;如日志记录、权限校验、性能监控等&#xff09;&#xff0c;是构建可观测、可治理系统的关键需求。Dubbo通过Filter接口实现了面向切面编…

linux安装nginx和前端部署vue项目

1、打包前端项目 npm run build 执行完后会在根目录下生成一个dist文件夹&#xff0c;这个dist文件夹就是我们后面要部署到nginx的东西。 2、将dist文件夹上传到服务器中 自己建一个目录&#xff0c;上传即可&#xff08;尽量不要在root目录下&#xff0c;可能涉及权限问题…

软件设计师“数据流图”真题考点分析——求三连

数据流图考点分析 1. 考点分值占比与趋势分析 综合知识题分值统计表 年份考题数量分值分值占比考察重点2018111.33%数据流图基本元素2019222.67%数据流图绘制原则2020111.33%数据流图与控制流图的区别2021334.00%数据字典与数据流图的关系2022222.67%分层数据流图的分解原则…

基于R语言的贝叶斯网络模型实践技术应用:开启科研新视角

在现代科研领域&#xff0c;变量间的因果关系推断是生态学、环境科学、医学等多学科研究的核心问题。然而&#xff0c;传统的统计学方法往往只能揭示变量间的相关关系&#xff0c;而非因果关系。贝叶斯网络作为一种结合图论与统计学理论的新型模型&#xff0c;不仅能够统合多种…

【Git】远程操作

Git 是一个分布式版本控制系统 可以简单理解为&#xff0c;每个人的电脑上都是一个完整的版本库&#xff0c;这样在工作时&#xff0c;就不需要联网 了&#xff0c;因为版本库就在自己的电脑上。 因此&#xff0c; 多个人协作的方式&#xff0c;譬如说甲在自己的电脑上改了文件…

DeepSpeed简介及加速模型训练

DeepSpeed是由微软开发的开源深度学习优化框架&#xff0c;专注于大规模模型的高效训练与推理。其核心目标是通过系统级优化技术降低显存占用、提升计算效率&#xff0c;并支持千亿级参数的模型训练。 官网链接&#xff1a;deepspeed 训练代码下载&#xff1a;git代码 一、De…

openlayer:10点击地图上某些省份利用Overlay实现提示省份名称

实现点击地图上的省份&#xff0c;在点击经纬度坐标位置附近利用Overlay实现提示框提示相关省份名称。本文介绍了如何通过OpenLayers库实现点击地图上的省份&#xff0c;并在点击的经纬度坐标位置附近显示提示框&#xff0c;提示相关省份名称。首先&#xff0c;定义了两个全局变…

upload-labs通关笔记-第13关 文件上传之白名单POST法

目录 一、白名单过滤 二、%00截断 1.截断原理 2、截断条件 &#xff08;1&#xff09;PHP版本 < 5.3.4 &#xff08;2&#xff09;magic_quotes_gpc配置为Off &#xff08;3&#xff09;代码逻辑存在缺陷 三、源码分析 1、代码审计 &#xff08;1&#xff09;文件…

数据库健康监测器(BHM)实战:如何通过 HTML 报告识别潜在问题

在数据库运维中,健康监测是保障系统稳定性与性能的关键环节。通过 HTML 报告,开发者可以直观查看数据库的运行状态、资源使用情况与潜在风险。 本文将围绕 数据库健康监测器(Database Health Monitor, BHM) 的核心功能展开分析,结合 Prometheus + Grafana + MySQL Export…

Oracle 11g 单实例使用+asm修改主机名导致ORA-29701 故障分析

解决 把服务器名修改为原来的&#xff0c;重启服务器。 故障 建表空间失败。 分析 查看告警日志 ORA-1119 signalled during: create tablespace splex datafile ‘DATA’ size 2000M… Tue May 20 18:04:28 2025 create tablespace splex datafile ‘DATA/option/dataf…

OpenCV CUDA模块图像过滤------用于创建一个最大值盒式滤波器(Max Box Filter)函数createBoxMaxFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 createBoxMaxFilter()函数创建的是一个 最大值滤波器&#xff08;Maximum Filter&#xff09;&#xff0c;它对图像中每个像素邻域内的像素值取最…

Redis数据库-消息队列

一、消息队列介绍 二、基于List结构模拟消息队列 总结&#xff1a; 三、基于PubSub实现消息队列 (1)PubSub介绍 PubSub是publish与subscribe两个单词的缩写&#xff0c;见明知意&#xff0c;PubSub就是发布与订阅的意思。 可以到Redis官网查看通配符的书写规则&#xff1a; …

破解充电安全难题:智能终端的多重防护体系构建

随着智能终端的普及&#xff0c;充电安全问题日益凸显。从电池过热到短路起火&#xff0c;充电过程中的安全隐患不仅威胁用户的生命财产安全&#xff0c;也制约了行业的发展。如何构建一套高效、可靠的多重防护体系&#xff0c;成为破解充电安全难题的关键。通过技术创新和系统…

apptrace 三大策略,助力电商 App 在 618 突围

随着 5 月 13 日 “618” 电商大促预售战的打响&#xff0c;各大平台纷纷祭出百亿补贴、消费券等大招&#xff0c;投入超百亿流量与数十亿现金&#xff0c;意图在这场年度商战中抢占先机。但这场流量争夺战远比想象中艰难&#xff0c;中国互联网络信息中心数据显示&#xff0c;…

SuperVINS:应对挑战性成像条件的实时视觉-惯性SLAM框架【全流程配置与测试!!!】【2025最新版!!!!】

一、项目背景及意义 SuperVINS是一个改进的视觉-惯性SLAM&#xff08;同时定位与地图构建&#xff09;框架&#xff0c;旨在解决在挑战性成像条件下的定位和地图构建问题。该项目基于经典的VINS-Fusion框架&#xff0c;但通过引入深度学习方法进行了显著改进。 视觉-惯性导航系…