Pandas fillna() inplace 参数在不使用三重 For 循环的情况下无法工作
Pandas fillna() inplace Parameter Isn't Working Without Using a Triple For Loop
我正在尝试将 DataFrame 分成四个部分,并使用 fillna()
为每个部分估算四舍五入的平均值。我有两列,main_campus
和 degree_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,但我需要仔细检查这个。
有人知道这里发生了什么吗?
解决此类问题的一个好方法是简化您的代码。简化您的代码可以更容易地找到警告的来源:
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
来摆脱丑陋的嵌套循环。它与您的“不优雅”的第一个解决方案非常相似。所以你第一次就差一点了。
我们最终得到了四行代码和一个循环。我敢肯定,使用一些 pandas 魔法,您可以将其转换为一行。但是,从现在开始的一周或一个月或一年后,您仍然会理解这四行。此外,阅读您的代码的其他人将很容易理解它。 可读性很重要。
免责声明:我无法测试代码,因为您没有提供示例数据框。所以我的代码可能会因为打字错误而抛出错误。 minimal reproducible example 使回答问题变得容易得多。下次您 post 关于 SO 的问题时请考虑这一点。
我正在尝试将 DataFrame 分成四个部分,并使用 fillna()
为每个部分估算四舍五入的平均值。我有两列,main_campus
和 degree_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,但我需要仔细检查这个。
有人知道这里发生了什么吗?
解决此类问题的一个好方法是简化您的代码。简化您的代码可以更容易地找到警告的来源:
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
来摆脱丑陋的嵌套循环。它与您的“不优雅”的第一个解决方案非常相似。所以你第一次就差一点了。
我们最终得到了四行代码和一个循环。我敢肯定,使用一些 pandas 魔法,您可以将其转换为一行。但是,从现在开始的一周或一个月或一年后,您仍然会理解这四行。此外,阅读您的代码的其他人将很容易理解它。 可读性很重要。
免责声明:我无法测试代码,因为您没有提供示例数据框。所以我的代码可能会因为打字错误而抛出错误。 minimal reproducible example 使回答问题变得容易得多。下次您 post 关于 SO 的问题时请考虑这一点。