Здравствуйте, я пытаюсь объединить / свернуть два кадра данных. Я хотел бы объединить «dfDates» и «dfProducts», а затем развернуть продукты в группе / участниках «dfProducts» до даты, когда появится новая группа / участники. Я пытался использовать внешнее объединение между двумя кадрами данных, но я не знаю, как свернуть группы ...

Ниже приведено описание того, как выглядят кадры данных и как мне нужен dfFinal.

dfProducts

   Date      Product

2018-01-01      A  
2018-01-01      B 
2018-01-01      C 
2018-01-03      D
2018-01-03      E
2018-01-03      F

dfDates

   Date        

2018-01-01       
2018-01-02   
2018-01-03       
2018-01-04      

dfFinal

   Date      Product

2018-01-01      A  
2018-01-01      B 
2018-01-01      C 
2018-01-02      A  
2018-01-02      B 
2018-01-02      C 
2018-01-03      D
2018-01-03      E
2018-01-03      F
2018-01-04      D
2018-01-04      E
2018-01-04      F

0
Jose Filho 5 Окт 2019 в 19:02

2 ответа

Самый простой вариант, который я вижу, - сначала сгруппировать все по дате, затем переиндексировать в нужный диапазон, чтобы nan опустил пустые места, а затем заполнить их:

(
    df
    .groupby("Date")
    ['Product']
    .apply(list)
    .reindex(pd.date_range(start=dfDates['Date'].min(), end=dfDates['Date'].max(), freq='D'))
    .fillna(method='ffill')
    .explode()
)

2018-01-01    A
2018-01-01    B
2018-01-01    C
2018-01-02    A
2018-01-02    B
2018-01-02    C
2018-01-03    D
2018-01-03    E
2018-01-03    F
2018-01-04    D
2018-01-04    E
2018-01-04    F
Name: Product, dtype: object
2
Randy 5 Окт 2019 в 19:46
1
Был бы более общим, если бы вы использовали start=df['Date'].min() и end=df['Date'].max(), помимо этого хорошего ответа +1
 – 
Erfan
5 Окт 2019 в 19:42
Хорошее предложение - доработаю.
 – 
Randy
5 Окт 2019 в 19:46
Я попробовал этот метод, но код не работает и вернул мне следующую ошибку: AttributeError: объект «Серия» не имеет атрибута «взорваться».
 – 
Jose Filho
6 Окт 2019 в 03:43
Я обнаружил ошибку, связанную с "взрывом". Моих панд не было в текущей версии, значит, "взорвать" нельзя. Я обновил библиотеку, и теперь все работает :) Другой быстрый вопрос: если у моих 'dfProducts' есть другие столбцы (например,'ProductPrice ',' ProductDetail '...), как я могу взорвать этот фрейм данных?
 – 
Jose Filho
6 Окт 2019 в 16:29

Определите следующую функцию:

def getLastDateRows(dat, df):
    rows = df.query('Date == @dat')
    n = rows.index.size
    if n == 0:
        lastDat = df.Date[df.Date < dat].iloc[-1]
        rows = df.query('Date == @lastDat')
    return pd.DataFrame({ 'Date': dat, 'Product': rows.Product })

Затем примените его к каждому dfDates.Date и concat результаты:

pd.concat(dfDates.Date.apply(getLastDateRows, df=dfProducts)\
    .tolist(), ignore_index=True)

Результат такой, как и ожидалось.

Аппендикс

Решение, предложенное Рэнди , можно немного улучшить:

dfProducts.groupby('Date').Product.apply(list)\
    .reindex(dfDates.Date).ffill().explode().reset_index()

Отличия:

  • Переиндексировать dfDates.Date (а не весь диапазон), поэтому результат будет содержат только даты, представленные в dfDates , которые могут содержать преднамеренные «пробелы», например на выходные.
  • Последний вызов reset_index приводит к тому, что результатом является DataFrame (не Серия ).
0
Valdi_Bo 5 Окт 2019 в 21:03