1. 数据预处理核心逻辑解析
以下为数据预处理阶段的核心函数实现,主要用于完成缺失值填充与类别字段的结构化解析:
# ========== 1) 预处理 ==========
def prepare_mercari_basic(df: pd.DataFrame,
category_col: str = "category_name",
brand_fill: str = "No Brand",
desc_fill: str = "No description",
cat_fill: str = "Unknown",
keep_original_category: bool = True) -> pd.DataFrame:
"""
1) 填充 brand_name / item_description
2) 安全拆分 category_name -> cat1/cat2/cat3(兼容缺失/层级不全/过多)
"""
df = df.copy()
if "brand_name" in df.columns:
df["brand_name"] = df["brand_name"].fillna(brand_fill)
if "item_description" in df.columns:
df["item_description"] = df["item_description"].fillna(desc_fill)
if category_col in df.columns:
cats = (
df[category_col]
.fillna("")
.str.extract(r"([^/]*)(?:/([^/]*))?(?:/(.*))?")
.rename(columns={0: "cat1", 1: "cat2", 2: "cat3"})
)
cats = cats.replace("", np.nan).fillna(cat_fill)
if not keep_original_category:
df = df.drop(columns=[category_col])
df = pd.concat([df, cats], axis=1)
return df
def shrink_brands_for_ohe(df: pd.DataFrame, col: str = "brand_name", top_n: int = 4000) -> pd.DataFrame:
"""保留高频品牌,其余归为 'Other',降低 OHE 维度"""
df = df.copy()
if col not in df.columns:
return df
top = df[col].value_counts().nlargest(top_n).index
df[col] = np.where(df[col].isin(top), df[col], "Other")
return df
[此处为图片1]
2. 缺失值处理策略
根据前期分析,数据集中主要存在两类关键字段的缺失情况:品牌名称(brand_name)和商品描述(item_description)。针对这两类缺失,采用统一且明确的填充方式,避免引入噪声或偏差。
具体做法是使用语义清晰的占位符进行补全:
- 当品牌信息缺失时,统一标记为“No Brand”;
- 当商品描述为空时,则填充为“No description”。
相关代码如下所示:
if "brand_name" in df.columns:
df["brand_name"] = df["brand_name"].fillna(brand_fill) # No Brand
if "item_description" in df.columns:
df["item_description"] = df["item_description"].fillna(desc_fill) # No Description
3. 类别字段的结构化拆分
原始数据中的类别字段(如 category_name)以斜杠分隔的形式呈现,格式为:
Cat 1/Cat 2/Cat 3
然而该字段存在严重的不规则性:部分样本可能仅有两层分类(如 Cat 1/Cat 2),而另一些样本则可能包含四层甚至更多(如 Cat 1/Cat 2/Cat 3/Cat 4)。这种层级深度不一的情况给后续建模带来挑战。
为此,采取简化策略——仅提取前三级分类,并将所有超出第三级的内容合并至第三级。通过正则表达式实现安全拆分:
if category_col in df.columns:
cats = (
df[category_col]
.fillna("")
.str.extract(r"([^/]*)(?:/([^/]*))?(?:/(.*))?")
.rename(columns={0: "cat1", 1: "cat2", 2: "cat3"})
)
cats = cats.replace("", np.nan).fillna(cat_fill)
上述逻辑首先将空值替换为空字符串,随后利用正则匹配提取最多三个层级。若原始字符串少于三层,则对应位置置为 NaN 并最终填充为“Unknown”;若超过三层,则第三段捕获从第三个斜杠开始的所有内容,确保信息不丢失。
最后,新生成的三个分类字段(cat1、cat2、cat3)被合并回原数据集。若参数 keep_original_category 设为 False,则原始的 category_name 字段将被移除,以减少冗余。
4. 品牌归并处理
这一操作的核心逻辑较为直观。由于 Mercari 是一个综合性的二手商品交易平台,支持各类商品的上架交易(类似于国内的闲鱼),因此商品所涉及的品牌种类极为繁杂。在这些品牌中,部分属于高频出现的品牌,而另一些则极少被提及。当品牌类别数量过于庞大时,若直接进行独热编码(One-Hot Encoding),将导致特征维度急剧膨胀,给后续建模带来计算负担和过拟合风险。
为解决该问题,我们设定一个阈值,仅保留出现频率最高的前 N 个品牌,其余所有低频品牌统一归入“Other”类别。这种处理方式有效控制了特征空间的规模,同时保留了主要品牌的信息价值。
[此处为图片1]
完成上述步骤后,整个数据预处理流程即告一段落。尽管该数据集本身的字段数量不多,处理过程相对简洁,但已为后续工作打下坚实基础。接下来的文章中,我们将正式进入关键环节——特征工程的构建与优化。


雷达卡


京公网安备 11010802022788号







