pandas 合并具有两个单独条件的 Dataframe

pw136qt2  于 2023-04-28  发布在  其他
关注(0)|答案(2)|浏览(205)

我试图在https://www.kaggle.com/competitions/store-sales-time-series-forecasting的帮助下学习时间序列,但在合并时遇到了问题。除了holidays_events之外,我已经合并了其他所有内容。
所以我的merged_df.head()现在看起来像

id       date  store_nbr     family  sales  onpromotion  dcoilwtico  city     state type  cluster  transactions
  0 2013-01-01          1 AUTOMOTIVE    0.0            0         NaN Quito Pichincha    D       13           NaN
  1 2013-01-01          1  BABY CARE    0.0            0         NaN Quito Pichincha    D       13           NaN
  2 2013-01-01          1     BEAUTY    0.0            0         NaN Quito Pichincha    D       13           NaN
  3 2013-01-01          1  BEVERAGES    0.0            0         NaN Quito Pichincha    D       13           NaN
  4 2013-01-01          1      BOOKS    0.0            0         NaN Quito Pichincha    D       13           NaN

holidays_events.head()看起来像

date    type   locale locale_name                   description  transferred
2012-03-02 Holiday    Local       Manta            Fundacion de Manta        False
2012-04-01 Holiday Regional    Cotopaxi Provincializacion de Cotopaxi        False
2012-04-12 Holiday    Local      Cuenca           Fundacion de Cuenca        False
2012-04-14 Holiday    Local    Libertad     Cantonizacion de Libertad        False
2012-04-21 Holiday    Local    Riobamba     Cantonizacion de Riobamba        False

'locale_name'列包含一些城市名称,因为一些假期仅特定于某些城市。但还有一个值'Ecuador'应该适用于所有内容。
我尝试了下面的代码,但很明显,它只是一个大混乱,有很多重复的列

ecuador = holidays_events.loc[holidays_events["locale_name"] == "Ecuador"].copy()
nonecuador = holidays_events.loc[holidays_events["locale_name"] != "Ecuador"].copy()

merged_df = merged_df.merge(nonecuador, left_on=['date', 'city'], right_on=['date', 'locale_name'], how='left')
merged_df = merged_df.merge(ecuador, on='date', how='left')

所以我的问题是有没有什么方法可以将holiday_events合并到merged_df中,以便在'locale_name'列中包含值'Ecuador'的任何行都将合并到='date',而其他值将合并到left_on= ['date ','city'],right_on=['date','locale_name']?或者有没有什么解决方法?

elcex8rz

elcex8rz1#

这是一个有点不具体(和平的代码+输出将有助于)尝试和回答你的问题-尝试使用一个分裂由您的条件,而不是2合并命令。
类似于:

#  'Ecuador' in 'locale_name' column would be merged on='date' 
df1 = df.loc[df["locale_name"] == "Ecuador"].copy()
df2 = df.loc[df["locale_name"] != "Ecuador"].copy()

df1 = df1.merge(other, on = "date", how="left")
#other values would be merged left_on=['date', 'city'], right_on=['date', 'locale_name']
df2 = df2.merge(other, left_on=['date', 'city'], right_on=['date', 'locale_name'])

final_df = df1.append(df2)
ffx8fchx

ffx8fchx2#

如果你不想弄得一团糟,只需要明确地编写你想要实现的代码。我想一列包含节日名称就足够了:

完整解决方案

merged_df["holiday"] = False
for holiday in holiday_events.itertuples():
    if holiday.locale_name == "Ecuador":
        mask = True
    elif holiday.locale == "Regional":
        mask = merged_df["state"] == holiday.locale_name
    elif holiday.locale == "Local":
        mask = merged_df["city"] == holiday.locale_name
    date_mask = merged_df["date"] == holiday.date
    targets = merged_df.loc[date_mask & mask, "holiday"]
    assert not targets.any()
    targets = holiday.description

说明

merged_df["holiday"] = False用值False初始化列。则在添加第一项时,该列将立即填充“无”。
itertuples()是迭代DataFrame行的最简单方法。它将每一行转换为方便的namedtuple。您可以通过holiday.locale_name中的列名和属性访问访问namedtuple(行的副本)holiday的每个项。
对于第一行:

date    type   locale locale_name                   description  transferred
2012-03-02 Holiday    Local       Manta            Fundacion de Manta        False

if-elif链简化为:

if "Manta" == "Ecuador":  # False
        ...
    elif "Local" == "Regional":  # False
        ...
    elif "Local" == "Local":  # True
        mask = merged_df["city"] == "Manta"

maskdate_mask对象只是填充了TrueFalse值的Pandas系列对象。(在"Ecuador"子句中,我刚刚放了True。Pandas稍后会广播它。)
merged_df.loc[date_mask & mask, "holiday"]在两个掩码之间进行布尔与运算,使用结果掩码(形状相同)通过.loc索引行,从而导致查看“假日”列中的适当字段。
assert not targets.any()检查是否有任何字段已经填充。如果您的假期数据库有重复项,则可能会发生这种情况。如果这引发AssertionError,您需要考虑如何处理这些。(More on assert
targets = holiday.description将假日名称插入到targets标识的所有字段中。

字典替代

你可以通过使用字典而不是if-elif-chain来删除一点代码重复,从而保存一些字符。我假设整个国家都是holiday.locale == "National",但你必须在DataFrame中检查实际值是什么。

merged_df["holiday"] = False
locale_levels = {
    "National": "Ecuador",
    "Regional": merged_df["state"],
    "Local": merged_df["city"],
}
for holiday in holiday_events.itertuples():
    place_mask = locale_levels[holiday.locale] == holiday.locale_name
    date_mask = merged_df["date"] == holiday.date
    targets = merged_df.loc[date_mask & place_mask, "holiday"]
    assert not targets.any()
    targets = holiday.description

相关问题