同一Pandas+Scikit-Learn代码在Colab与VSCode运行结果差异原因
问题
我实现了一个继承自Scikit-Learn的BaseEstimator和TransformerMixin的ScoreTransformer类,在其purchase_date_score方法中通过Pandas进行数据处理,并将该Transformer纳入Pipeline执行。在Google Colab中运行时输出正常,但在VSCode中运行时,step2后的数据为空。已确认两个环境的Python和Pandas版本完全一致,请问导致该差异的原因是什么?
代码实现
from sklearn.pipeline import Pipeline from sklearn.base import BaseEstimator, TransformerMixin class ScoreTransformer(TransformerMixin, BaseEstimator): def __init__(self): pass def fit(self, X, y=None): return self def purchase_date_score(self, purchases): purchases['date_x'] = pd.to_datetime(purchases['FinishDate']) purchases['date_rank'] = purchases.sort_values(['uid','date_x'], ascending=False).groupby('uid')['date_x'].rank("dense", ascending=False).astype(int) print(f'step1 -----\n{purchases.head()}') df2 = purchases[purchases.groupby("bid")['uid'].transform('size') > 20].reset_index(drop=True) print(f'step2 -----\n{df2.head()}') df2 = df2[df2.groupby("uid")['bid'].transform('size') > 10].reset_index(drop=True) print(f'step3 -----\n{df2.head()}') df2 = df2[['uid', 'bid', 'date_rank']] df2['normal_rank'] = df2[['uid', 'date_rank']].groupby('uid')['date_rank'].transform(lambda x: round(x * 2 / x.max() + 3)) print(f'step4 -----\n{df2.head()}') return df2.drop(['date_rank'], axis=1) def transform(self, X, y=None): return self.purchase_date_score(X)
Pipeline调用代码
ranking_score_pipeline = Pipeline(([ ('score', ScoreTransformer()) ])) data = ranking_score_pipeline.fit_transform(data)
测试数据样例
uid bid FinishDate 0 41,5,2013-09-14 10:44:59.877 1 43,37,2013-09-21 11:53:20.193 2 43,45,2013-09-21 12:01:42.390 3 41,99,2013-11-18 18:37:52.190 4 75,99,2013-12-19 09:24:55.717
分析与解决方案
以下是可能导致环境差异的核心原因及修复建议:
- 数据加载格式不一致:你提供的测试数据每行是逗号分隔的字符串,若Colab中已正确将其解析为
uid、bid、FinishDate三列,但VSCode中未做分割处理(比如直接读取为单列),那么按bid分组时,每个组的唯一值都是整行字符串,分组后的size远小于20,直接导致step2后数据为空。 - Scikit-Learn版本差异:你仅确认了Python和Pandas版本一致,但Scikit-Learn版本可能存在区别。不同版本的Pipeline对Transformer输入数据的处理逻辑有细微差异,比如是否允许原地修改输入数据(你的代码直接在
purchases上新增列),部分版本会自动创建数据副本,导致后续分组逻辑失效。 - 数据类型不匹配:检查VSCode中
data的列类型,比如uid或bid是否被解析为数值型,而Colab中是字符串型?类型不一致会导致分组结果完全不同,若每个bid组的size都小于20,过滤后自然无数据。 - Pandas全局设置差异:两个环境的Pandas全局配置(如
mode.chained_assignment)可能不同,严格模式下的隐性警告或限制可能影响原地修改数据的逻辑,间接导致后续处理异常。
验证与修复步骤
- 在VSCode中打印
data.head(),确认数据是否被正确解析为三列,且uid、bid的类型符合预期。 - 执行
print(sklearn.__version__)对比两个环境的Scikit-Learn版本,统一版本后重新测试。 - 修改
purchase_date_score方法,避免原地修改输入数据,先创建副本:def purchase_date_score(self, purchases): # 创建数据副本,避免修改原输入数据 df = purchases.copy() df['date_x'] = pd.to_datetime(df['FinishDate']) df['date_rank'] = df.sort_values(['uid','date_x'], ascending=False).groupby('uid')['date_x'].rank("dense", ascending=False).astype(int) print(f'step1 -----\n{df.head()}') df2 = df[df.groupby("bid")['uid'].transform('size') > 20].reset_index(drop=True) # 后续逻辑均使用df副本 print(f'step2 -----\n{df2.head()}') df2 = df2[df2.groupby("uid")['bid'].transform('size') > 10].reset_index(drop=True) print(f'step3 -----\n{df2.head()}') df2 = df2[['uid', 'bid', 'date_rank']] df2['normal_rank'] = df2[['uid', 'date_rank']].groupby('uid')['date_rank'].transform(lambda x: round(x * 2 / x.max() + 3)) print(f'step4 -----\n{df2.head()}') return df2.drop(['date_rank'], axis=1) - 执行
print(pd.get_option('mode.chained_assignment'))对比两个环境的Pandas设置,确保配置一致。
内容的提问来源于stack exchange,提问作者Kia Lia
相关产品推荐
相关产品推荐

