You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一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)可能不同,严格模式下的隐性警告或限制可能影响原地修改数据的逻辑,间接导致后续处理异常。

验证与修复步骤

  1. 在VSCode中打印data.head(),确认数据是否被正确解析为三列,且uid、bid的类型符合预期。
  2. 执行print(sklearn.__version__)对比两个环境的Scikit-Learn版本,统一版本后重新测试。
  3. 修改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)
    
  4. 执行print(pd.get_option('mode.chained_assignment'))对比两个环境的Pandas设置,确保配置一致。

内容的提问来源于stack exchange,提问作者Kia Lia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 01:55:17