【问题标题】:Pandas fillna() inplace Parameter Isn't Working Without Using a Triple For Loop如果不使用三重 For 循环,Pandas fillna() 就地参数不起作用
【发布时间】:2020-11-02 03:15:49
【问题描述】:

我正在尝试将 DataFrame 分成四个部分,并使用 fillna() 为每个部分估算四舍五入的平均值。我有两列,main_campusdegree_type 我要过滤,每列有两个唯一值。所以在他们之间,我应该能够将 DataFrame 过滤成两组。

我首先使用三重 for 循环(见下文)执行此操作,这似乎有效,但是当我尝试以更优雅的方式执行此操作时,我收到了 SettingWithCopy 警告,我无法通过使用来修复.loc.copy(),即使将inplace 设置为True,也不会填充缺失值。这是后一种方法的代码:

# Imputing mean values for main campus BA students
df[(df.main_campus == 1) &
            (df.degree_type == 'BA')] = df[(df.main_campus == 1) &
            (df.degree_type == 'BA')].fillna(
                df[(nulled_data.main_campus == 1) &
                            (df.degree_type == 'BA')
                            ].mean(),
                     inplace=True)
            
# Imputing mean values for main campus BS students
df[(df.main_campus == 1) &
            (df.degree_type == 'BS')] = df[(df.main_campus == 1) &
            (df.degree_type == 'BS')].fillna(
                df[(df.main_campus == 1) &
                            (df.degree_type == 'BS')
                            ].mean(),
                     inplace=True)
            
# Imputing mean values for downtown campus BA students
df[(df.main_campus == 0) &
            (df.degree_type == 'BA')] = df[(df.main_campus == 0) &
            (df.degree_type == 'BA')].fillna(
                df[(df.main_campus == 0) &
                            (df.degree_type == 'BA')
                            ].mean(),
                     inplace=True)

# Imputing mean values for downtown campus BS students          
df[(df.main_campus == 0) &
            (df.degree_type == 'BS')] = df[(df.main_campus == 0) &
            (df.degree_type == 'BS')].fillna(
                df[(df.main_campus == 0) &
                            (df.degree_type == 'BS')
                            ].mean(),
                     inplace=True)      

我应该提到之前的代码经历了几次迭代,尝试它而不将其设置回切片,有和没有inplace等。

下面是带有三重 for 循环的代码:

imputation_cols = [# all the columns I want to impute]

for col in imputation_cols:

  for i in [1, 0]:

    for path in ['BA', 'BS']:

      group = ndf.loc[((df.main_campus == i) &
                               (df.degree_type == path)), :]
      
      group = group.fillna(value=round(group.mean()))

      df.loc[((df.main_campus == i) &
                               (df.degree_type == path)), :] = group

值得一提的是,我认为在三重 for 循环代码中使用 group 变量也是为了帮助填充的 NaN 值实际设置回 DataFrame,但我需要仔细检查。

有人知道这里发生了什么吗?

【问题讨论】:

    标签: python pandas fillna in-place pandas-loc


    【解决方案1】:

    解决此类问题的一个好方法是简化您的代码。简化代码可以更轻松地找到警告的来源:

    group1 = (df.main_campus == 1) & (df.degree_type == 'BA')
    group2 = (df.main_campus == 1) & (df.degree_type == 'BS')
    group3 = (df.main_campus == 0) & (df.degree_type == 'BA')
    group4 = (df.main_campus == 0) & (df.degree_type == 'BS')
    
    # Imputing mean values for main campus BA students
    df.loc[group1, :] = df.loc[group1, :].fillna(df.loc[group1, :].mean())  # repeat for other groups
    

    现在您可以更清楚地看到问题所在。您正在尝试将 df 的平均值写回 df。 Pandas 发出警告,因为您用于计算平均值的切片可能与更改的数据帧不一致。在您的情况下,它会产生正确的结果。但是您的数据框的一致性存在风险。

    你可以通过预先计算平均值来解决这个问题:

    group1_mean = df.loc[group1, :].mean()
    df.loc[group1, :] = df.loc[group1, :].fillna(group1_mean)
    

    在我看来,这使代码更加清晰。但是您仍然有四个组(group1、group2、...)。使用循环的明确标志:

    from itertools import product
    
    for campus, degree in product([1, 0], ['BS', 'BA']):
        group = (df.main_campus == campus) & (df.degree_type == degree)
        group_mean = df.loc[group, :].mean()
        df.loc[group, :] = df.loc[group, :].fillna(group_mean)
    

    我使用了来自 itertools 的 product 来摆脱丑陋的嵌套循环。它与您的“不雅”第一个解决方案非常相似。所以你第一次几乎就在那里。

    我们最终得到了四行代码和一个循环。我敢肯定,通过一些熊猫魔法,您可以将其转换为一行。但是,从现在开始的一周、一个月或一年内,您仍然会理解这四行。此外,阅读您的代码的其他人会很容易理解它。 可读性很重要。


    免责声明:我无法测试代码,因为您没有提供示例数据框。所以我的代码可能会因为拼写错误而引发错误。 minimal reproducible example 使回答问题变得更加容易。下次您在 SO 上发布问题时请考虑这一点。

    【讨论】:

    • 非常感谢您的回答!在这种情况下,将平均值写回 df 是否会产生正确的结果,因为它是 mean 具体而言,并且添加数学平均值不会改变整个列的平均值?
    • 是的,我认为写回平均值应该会产生正确的结果,因为它是平均值。对于其他操作(例如求和),预期的行为尚不清楚。关于 df:共享数据框非常简单。只需使用 print(df) 并将其复制到问题中即可。欲了解更多信息see this SO post
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-14
    • 2022-12-10
    • 1970-01-01
    • 2017-04-13
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多