当前位置: 首页 > news >正文

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

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 tqdmfor 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)) # 缺失值降序查看10print(f"Duplicated rows: {df.duplicated().sum()}") # 查看重复行的个数#查看缺失值的热力图plt.figure(figsize=(10, 6)) #大小10×6sns.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值)# 更新进度条:每处理一个组合,进度条前进1for 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) + 1pbar.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: float64print(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.columnsencoder = TargetEncoder(n_folds=5, seed=seed, stat="mean")# Apply Target Encodingfor 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)

相关文章:

  • 基于C语言的歌曲调性检测技术解析
  • NX二次开发——设置对象的密度(UF_MODL_set_body_density)
  • redisson分布式锁实现原理归纳总结
  • JAVA EE_HTTP
  • 仅需三张照片即可生成沉浸式3D购物体验?谷歌电商3D方案全解析
  • 信息系统项目管理师高级-软考高项案例分析备考指南(2023年案例分析)
  • 【通用智能体】Search Tools:Open Deep Research 项目实战指南
  • Ubuntu 安装 squid
  • 【MySQL】第五弹——表的CRUD进阶(三)聚合查询(上)
  • AI:人形机器人的应用场景以及商业化落地潜力分析
  • 神经网络与深度学习第六章--循环神经网络(理论)
  • 16 C 语言布尔类型与 sizeof 运算符详解:布尔类型的三种声明方式、执行时间、赋值规则
  • 业务系统上线为什么这么难
  • Level2.8蛇与海龟(游戏)
  • 浅谈前端架构设计与工程化
  • C语言_编译全攻略_从原理到实战的深度解析
  • 如何利用 Python 获取京东商品 SKU 信息接口详细说明
  • 深度学习模型基本框架
  • 谷歌浏览器(Google Chrome)136.0.7103.93便携增强版|Win中文|安装教程
  • 【Redis】零碎知识点(易忘 / 易错)总结回顾
  • 台湾关闭最后的核电,岛内担忧“非核家园”缺电、涨电价困局难解
  • 80后女博士黄双燕拟提名为内蒙古盟市政府(行署)副职人选
  • 体坛联播|热刺追平单赛季输球纪录,世俱杯或创收20亿美元
  • 四川内江警方通报一起持刀伤人致死案:因车辆停放引起,嫌犯被抓获
  • “AD365特应性皮炎疾病教育项目”启动,助力提升认知与规范诊疗
  • 齐白石精品在波士顿展出,“白石画屋”呈现水墨挥洒