#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