如何根据匹配辅助数据框值的条件在主数据框的列中填充 NaN 以使用多个填充值填充 NaN

How to Fill NaNs in Column of Main Dataframe Based On Conditions Matching Secondary Dataframe of Values to Fill NaNs With Multiple Filler Values

我需要根据 groupbymean 函数创建的第二个数据框在我的主数据框中填充 NA 值。我的原始数据框有大约 1.5K 个 NaN 我需要填充,所以这需要在大规模上可重现。我创建了一个假的数据框,它是使用假场景对我的数据进行的简短而肮脏的模仿。我不能和你分享我的真实数据。

我的大致思路是:

main_data[
          (main_data["Animal_Type"] == mean_data["Animal_Type"]) & 
          (main_data["Cost_Type"] == mean_data["Cost_Type"])
         ] = main_data["Price"].fillna(mean_data["Price"])

显然,这行不通,但这是我的逻辑运作方式的一般要点。我找到了 [他的答案][1],但我看不到如何将其正确应用于我的问题。许多答案涉及 mask 或假设我的数据非常小,只有一个值可以替换我所有的 NaN。在我的原始数据集中,我有大约 50 种不同的方法,每个“成本类型”都与“动物类型”唯一配对。我的原始数据框大约有 30K 个观察值,其中也充满了独特的观察值。我可以映射,但这仅适用于单个列。我对编码还很陌生,所以很多其他答案对我来说太复杂了,我也无法理解和改变。

main_data

mean_data.head(10)

   **Pet_ID Animal_Type Cost_Type   Price**
0   101     Goat        Housing     6.0
1   102     Dog         Housing     6.0
2   103     Horse       Housing     NaN
3   104     Horse       Housing     5.0
4   105     Goat        Housing     3.0
5   106     Dog         Feeding     3.0
6   107     Cat         Feeding     6.0
7   108     Horse       Housing     6.0
8   109     Hamster     Feeding     5.0
9   110     Horse       Feeding     3.0

mean_data

    Animal_Type Cost_Type   Price
0   Cat         Feeding     4.500000
1   Cat         Housing     5.000000
2   Chicken     Feeding     5.000000
3   Chicken     Housing     4.500000
4   Dog         Feeding     3.000000
5   Dog         Housing     6.000000
6   Goat        Feeding     5.000000
7   Goat        Housing     5.000000
8   Hamster     Feeding     5.250000
9   Hamster     Housing     3.000000
10  Horse       Feeding     3.500000
11  Horse       Housing     5.666667
12  Rabit       Feeding     3.000000
13  Rabit       Housing     3.000000

我的可重现代码:

random.seed(10)

random.seed(10)

main_data = pd.DataFrame(columns = ["Pet_ID", "Animal_Type", "Cost_Type", "Price", "Cost"])

main_data["Pet_ID"] = pd.Series(list(range(101,150)))
main_data["Animal_Type"] = main_data.Animal_Type.apply(lambda x: random.choice(["Dog", "Cat", "Rabit", "Horse", "Goat", "Chicken", "Hamster"])) 
main_data["Cost_Type"] = main_data.Animal_Type.apply(lambda x: random.choice(["Housing", "Feeding"])) 
main_data["Price"] = main_data.Price.apply(lambda x: random.choice([3, 5, 6, np.nan])) 
main_data["Cost"] =  main_data.Cost.apply(lambda x: random.choice([2, 1, 3, np.nan])) 

mean_data = main_data.groupby(["Animal_Type", "Cost_Type"])["Price"].mean().reset_index()

编辑: 我已经将两个解决方案放在一起,但我不会说哪个更优雅或更可靠。可能也不是最有效的。

main_data = pd.merge(
    main_data,
    mean_data,
    on = ["Animal_Type", "Cost_Type"],
    how = "left"
)

main_data["Price_z"] = main_data["Price_x"].fillna(main_data["Price_y"])

编辑 2:我添加了带有 NaN 的“成本”列。我不想触及此列,但希望对我们用于价格列的此列使用相同的方法。 [1]:

I need to fill NA values in my main data frame based on a second dataframe I created by the groupby and mean functions.

您不需要这一步。您可以一步完成此操作,方法是将多个数据帧分组,对每个单独的数据帧应用均值,然后仅在该数据帧内填充 NA 值。

因此,不要创建 mean_data 数据框,而是这样做:

def fill_by_mean(df):
    df["Price"] = df["Price"].fillna(df["Price"].mean())
    return df

main_data = main_data.groupby(["Animal_Type", "Cost_Type"]).apply(fill_by_mean)

每次调用 fill_by_mean() 都会看到一个如下所示的数据帧:

    Pet_ID Animal_Type Cost_Type  Price
11     112       Rabit   Feeding    NaN
34     135       Rabit   Feeding    3.0
38     139       Rabit   Feeding    3.0

然后它获取价格列的平均值并使用它填充 NA 值。然后 Groupby 将所有单独的数据帧连接在一起。