Сравнение фреймов данных и учет их различий

#python #pandas #dataframe

#python #панды #фрейм данных

Вопрос:

У меня сложная проблема, но я постараюсь объяснить ее более подробно. У меня есть следующие 2 фрейма данных, и мне нужно провести небольшое сравнение и поместить разницу в другой фрейм данных. Критерии для сравнения можно увидеть ниже.

 initial = pd.DataFrame({'ProductID': ['123', '456', '789', '000','231'],
                     'ProductName': ['Apple','Pear','Mango','Banana','Jackfruit'],
                     'DiscountedPrice': ['0.99', '1.00', '1.50', '2.10','2.35'],
                      'DiscountStartDate': ['30/01/2020', '21/06/2020', '01/01/2020', '10/11/2020','05/05/2020'],
                      'DiscountEndDate': ['25/03/2020', '30/07/2020', '30/01/2020', '12/12/2020','06/06/2020']}) 

updated = pd.DataFrame({'ProductID': ['123', '456', '789', '000','231'],
                     'ProductName': ['Apple','Pear','Mango','Banana','Jackfruit'],
                     'DiscountedPrice': ['0.53', '1.00', '0.99', '2.00','2.35'],
                      'DiscountStartDate': ['30/01/2020', '21/06/2020', '15/01/2020', '30/11/2020','09/10/2020'],
                      'DiscountEndDate': ['25/03/2020', '30/07/2020', '30/01/2020', '12/12/2020','31/10/2020']}) 
 
 

Критериями сравнения являются;

(1) Если цена со скидкой и дата начала / окончания для обоих фреймов данных одинаковы, игнорируйте.

(2) Если цена со скидкой одинакова, но дата начала / окончания отличается, мне нужно будет внести обе записи в мой фрейм данных «изменения»

(3) Если цена со скидкой для обоих фреймов данных различна, но даты начала и окончания одинаковы, мне нужно будет использовать даты со скидкой и начала / окончания из «обновленного» фрейма данных в мой фрейм данных «изменения»

(4) Если цена со скидкой отличается, а даты их начала / окончания каким-то образом перекрываются, мне нужно было бы настроить конечную дату начального значения на -1 от даты начала обновления и перенести обе записи в мой фрейм данных «изменения»

В принципе, вывод фрейма данных «изменения» должен выглядеть как таблица ниже.

ProductID ProductName Цена со скидкой DiscountStartDate DiscountEndDate
123 Apple 0.53 30/01/2020 25/03/2020
789 Mango 1.50 01/01/2020 14/01/2020
789 Mango 0.99 15/01/2020 30/01/2020
000 Банан 2.10 10/11/2020 29/11/2020
000 Банан 2.00 30/11/2020 12/12/2020
231 Джекфрут 2.35 05/05/2020 06/06/2020
231 Джекфрут 2.35 09/10/2020 31/10/2020

Может кто-нибудь помочь мне с этим?

Ответ №1:

Объедините два фрейма данных, чтобы логика могла быть применена для идентификации всех четырех случаев. При выявлении случаев дата может быть изменена, а результаты объединены вместе. Добавили, в каком случае это связано с изменением фрейма данных для прозрачности.

 initial = pd.DataFrame({'ProductID': ['123', '456', '789', '000','231'],
                     'ProductName': ['Apple','Pear','Mango','Banana','Jackfruit'],
                     'DiscountedPrice': ['0.99', '1.00', '1.50', '2.10','2.35'],
                      'DiscountStartDate': ['30/01/2020', '21/06/2020', '01/01/2020', '10/11/2020','05/05/2020'],
                      'DiscountEndDate': ['25/03/2020', '30/07/2020', '30/01/2020', '12/12/2020','06/06/2020']}) 

updated = pd.DataFrame({'ProductID': ['123', '456', '789', '000','231'],
                     'ProductName': ['Apple','Pear','Mango','Banana','Jackfruit'],
                     'DiscountedPrice': ['0.53', '1.00', '0.99', '2.00','2.35'],
                      'DiscountStartDate': ['30/01/2020', '21/06/2020', '15/01/2020', '30/11/2020','09/10/2020'],
                      'DiscountEndDate': ['25/03/2020', '30/07/2020', '30/01/2020', '12/12/2020','31/10/2020']}) 
 
initial["DiscountStartDate"] = pd.to_datetime(initial["DiscountStartDate"])
initial["DiscountEndDate"] = pd.to_datetime(initial["DiscountEndDate"])
updated["DiscountStartDate"] = pd.to_datetime(updated["DiscountStartDate"])
updated["DiscountEndDate"] = pd.to_datetime(updated["DiscountEndDate"])


# merge two dataframes so that values can be identified
dfcat = (initial
 .merge(updated, on=["ProductID"], suffixes=("_i","_u"))
# cascading logic to mark which each of the 4 cases
 .assign(cat=lambda dfa: np.where(dfa["DiscountStartDate_i"].eq(dfa["DiscountStartDate_u"])
                                  amp;dfa["DiscountEndDate_i"].eq(dfa["DiscountEndDate_u"])
                                  amp;dfa["DiscountedPrice_i"].eq(dfa["DiscountedPrice_u"])
                                  ,"case1",
                                  # no need to check dates different - done in case1
                                  np.where(dfa["DiscountedPrice_i"].eq(dfa["DiscountedPrice_u"])
                                           ,"case2",
                                np.where(dfa["DiscountEndDate_i"].eq(dfa["DiscountEndDate_u"])
                                  amp;dfa["DiscountStartDate_i"].eq(dfa["DiscountStartDate_u"])

                                  ,"case3", "case4")))
# case 4, modify EndDate
        ,DiscountEndDate_i=lambda dfa: np.where(dfa["cat"].eq("case4"),
                                                dfa["DiscountStartDate_u"] - pd.to_timedelta(1,unit="d"),
                                                dfa["DiscountEndDate_i"])

 
))

# utility to filter data and rename columns for each of the cases
def chngrows(df, case, ind):
    return (df
            .query(f"cat.isin(['{case}'])")
            .loc[:,["ProductID"] [c for c in dfcat.columns if ind in c]]
            .rename(columns={c:c.replace(ind,"") for c in dfcat.columns if ind in c})
            .assign(cat=f"{case}{ind}")
           )


changes = pd.concat([
    chngrows(dfcat, "case2", "_i"),
    chngrows(dfcat, "case2", "_u"),
    chngrows(dfcat, "case3", "_u"),
    chngrows(dfcat, "case4", "_i"),
    chngrows(dfcat, "case4", "_u"),
]).sort_values(["ProductID","cat"])

 

вывод

 ProductID ProductName DiscountedPrice DiscountStartDate DiscountEndDate      cat
      000      Banana            2.10        2020-10-11      2020-11-29  case4_i
      000      Banana            2.00        2020-11-30      2020-12-12  case4_u
      123       Apple            0.53        2020-01-30      2020-03-25  case3_u
      231   Jackfruit            2.35        2020-05-05      2020-06-06  case2_i
      231   Jackfruit            2.35        2020-09-10      2020-10-31  case2_u
      789       Mango            1.50        2020-01-01      2020-01-14  case4_i
      789       Mango            0.99        2020-01-15      2020-01-30  case4_u