根据另一列的值,使用 Pandas 进行条件填充。

3

我正在处理bigmart数据集,希望能根据另一列的值替换缺失值,具体来说:

     Outlet_Size  sales_bin
0         Medium  3000-4000
1         Medium     0-1000
2         Medium  2000-3000
3            NaN     0-1000
4           High     0-1000
...          ...        ...
8518        High  2000-3000
8519         NaN     0-1000
8520       Small  1000-2000
8521      Medium  1000-2000
8522       Small     0-1000

So if train[“Outlet_Size”] value is a NaN and train[“sales_bin”] is  “0-1000”
train[“Outlet_Size”] value shoud become “Small”
else == Medium

但我真的不知道如何编写它,而且我发现的所有信息都让我感到困惑

这可行吗?怎么做?

非常感谢

3个回答

2
您可以使用pandas.Series.map而不是numpy.where
对于这些简单情况,pandas.Series.map似乎更方便,可以使用字典(例如{'0-1000':'Small','2000-3000':'High'})使多个替换更容易和明确。
numpy.where设计用于处理更多的逻辑(例如:如果a < 5,则a ^ 2),但在OP用例中并不是非常有用,但会带来一些成本,例如使多个替换的嵌套if-else难以处理。
步骤:
将以下文本翻译成中文:
  1. 使用pandas.Series.isna()生成一个掩码,标记pandas.DataFrame中缺失'Outlet_Size'的子集;
  2. 定义一个映射字典,例如从'0-1000'到'Small';
  3. 使用pandas.Series.map和定义的字典作为args参数,替换定义的pandas.DataFrame子集中的'Outlet_Size'值。
  4. 使用pandas.Series.fillna()捕获未映射的缺失'Outlet_Size'并将其填充为默认值。

示例:

import pandas as pd
import numpy as np
fake_dataframe = pd.DataFrame({
    'Outlet_Size' : ['Medium', 'Medium', 'Medium', np.nan, 'High', 'High', np.nan, 'Small', 'Medium', 'Small', np.nan, np.nan],
    'sales_bin': ['3000-4000', '0-1000', '2000-3000', '0-1000', '0-1000', '2000-3000', '0-1000', '1000-2000', '1000-2000', '0-1000', '2000-3000', '1000-2000']
})
missing_mask = fake_dataframe['Outlet_Size'].isna()
mapping_dict = dict({'0-1000': 'Small'})
fake_dataframe.loc[missing_mask, 'Outlet_Size'] = fake_dataframe.loc[missing_mask, 'sales_bin'].map(mapping_dict)
fake_dataframe['Outlet_Size'] = fake_dataframe['Outlet_Size'].fillna('Medium')
print(fake_dataframe)
   Outlet_Size  sales_bin
0       Medium  3000-4000
1       Medium     0-1000
2       Medium  2000-3000
3        Small     0-1000
4         High     0-1000
5         High  2000-3000
6        Small     0-1000
7        Small  1000-2000
8       Medium  1000-2000
9        Small     0-1000
10      Medium  2000-3000
11      Medium  1000-2000

具有多重插补的示例:
import pandas as pd
import numpy as np
fake_dataframe = pd.DataFrame({
    'Outlet_Size' : ['Medium', 'Medium', 'Medium', np.nan, 'High', 'High', np.nan, 'Small', 'Medium', 'Small', np.nan, np.nan],
    'sales_bin': ['3000-4000', '0-1000', '2000-3000', '0-1000', '0-1000', '2000-3000', '0-1000', '1000-2000', '1000-2000', '0-1000', '2000-3000', '1000-2000']
})
missing_mask = fake_dataframe['Outlet_Size'].isna()
mapping_dict = dict({'0-1000': 'Small', '2000-3000': 'High'})
fake_dataframe.loc[missing_mask, 'Outlet_Size'] = fake_dataframe.loc[missing_mask, 'sales_bin'].map(mapping_dict)
fake_dataframe['Outlet_Size'] = fake_dataframe['Outlet_Size'].fillna('Medium')
print(fake_dataframe)
    Outlet_Size sales_bin
0   Medium  3000-4000
1   Medium  0-1000
2   Medium  2000-3000
3   Small   0-1000
4   High    0-1000
5   High    2000-3000
6   Small   0-1000
7   Small   1000-2000
8   Medium  1000-2000
9   Small   0-1000
10  High    2000-3000
11  Medium  1000-2000

你好SuoufianeK,非常感谢你的回答。你提出的建议似乎非常有趣,因为它允许根据多个条件填充NaN。不幸的是 - 我不知道我是否做错了什么 - 我收到了一个错误:'missing = train["Outlet_Size"].isna() mapping_dict = dict({'0-1000': 'Small', '2000-3000' : 'High'}) na_value = None ',然后 'train[missing, 'Outlet_Size'] = train.loc[missing, 'sales_bin'].map(mapping_dict, na_action='Medium') ' 然后出现 TypeError: 'Series' objects are mutable, thus they cannot be hashed。 - Cesco83
你好。谢谢你的回答。我刚刚进行了编辑,删除了不必要的na_action。我还提供了一个带有多个插补的示例,使用 dict({'0-1000': 'Small', '2000-3000': 'High'})。 你之所以出错是因为你忘记在train[missing, 'Outlet_Size'] = train.loc[missing, 'sales_bin'].map(mapping_dict)中加入 .loc。 - SoufianeK
非常感谢!它完美运行,并帮助我更好地理解pandas。 - Cesco83

1

根据Shubham Sharma的建议(使用np.select函数),并使用“Item_Outlet_Sales”特征而不是“sales_bin”

因此:

        Outlet_Size  Item_Outlet_Sales
0         Medium          3735.1380
1         Medium           443.4228
2         Medium          2097.2700
3            NaN           732.3800
4           High           994.7052
...          ...                ...
8518        High          2778.3834
8519         NaN           549.2850
8520       Small          1193.1136
8521      Medium          1845.5976
8522       Small           765.6700 

    missing = train["Outlet_Size"].isna()
    condlist = [train.loc[missing, "Outlet_Size"] & train.loc[missing,'sales_bin'] <=1000, 
    train.loc[missing, "Outlet_Size"] & train.loc[missing,'sales_bin'] > 1000] 
    choicelist = ["Small", "Medium"] #PS, If I got it well it is possible to add as # many contiontions as wanted, as long condlist and choicelist has the same lenght 
    train.loc[missing, 'Outlet_Size'] = np.select(condlist, choicelist)
    train["Outlet_Size"].value_counts(dropna=False)

Small     4798
Medium    2793
High       932

非常感谢您的建议以及这个精彩的论坛存在:)

1

使用Series.isna创建布尔掩码,然后使用np.where + Series.eq根据sales_bin等于0-1000的条件从SmallMedium中选择选项:

m = df['Outlet_Size'].isna()
df.loc[m, 'Outlet_Size'] = np.where(df.loc[m, 'sales_bin'].eq('0-1000'), 'Small', 'Medium')

结果:

print(df)
     Outlet_Size  sales_bin
0         Medium  3000-4000
1         Medium     0-1000
2         Medium  2000-3000
3          Small     0-1000
4           High     0-1000
8518        High  2000-3000
8519       Small     0-1000
8520       Small  1000-2000
8521      Medium  1000-2000
8522       Small     0-1000

1
你好Shubham Sharma,非常感谢你的答案,它有效:)。我能否询问您是否可以在多个条件下使用此方法?我尝试了 'train.loc[m,'Outlet_Size'] = np.where(train.loc[m,'sales_bin'].eq("0-1000"),“ Small”, train.loc[m,'sales_bin'].eq("2000-3000"),“ High”,“ Medium”)' 但是它没有奏效。再次感谢。 - Cesco83
不行,这种情况下你必须使用 np.select - Shubham Sharma
1
非常感谢!我会尝试使用np.select。 - Cesco83

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接