#python #pandas
#python #панды
Вопрос:
У меня есть фрейм данных с датами «От» и «До» для каждой строки, как в примере ниже:
------------ ------------ --------- ----------- ----- -----
| From | Until | Product | BaseValue | Tax | Int |
------------ ------------ --------- ----------- ----- -----
| 01/01/2020 | 01/02/2020 | A | 200 | 50 | 10 |
| 01/01/2020 | 01/02/2020 | B | 500 | 15 | 5 |
| 01/01/2020 | 01/02/2020 | C | 150 | 10 | 2 |
------------ ------------ --------- ----------- ----- -----
Тем не менее, мне нужно «расплавить» даты из каждой строки, создавая одну новую строку для каждой даты, которая помещается между «От» и «До».
Например, ожидаемый результат:
------------ --------- ----------- ----- -----
| Date | Product | BaseValue | Tax | Int |
------------ --------- ----------- ----- -----
| 01/01/2020 | A | 200 | 50 | 10 |
| 02/01/2020 | A | 200 | 50 | 10 |
| 03/01/2020 | A | 200 | 50 | 10 |
| ... | ... | ... | ... | ... |
| 01/02/2020 | A | 200 | 50 | 10 |
| 01/01/2020 | B | 500 | 15 | 5 |
| 02/01/2020 | B | 500 | 15 | 5 |
| 03/01/2020 | B | 500 | 15 | 5 |
| ... | ... | ... | ... | ... |
| 01/02/2020 | B | 500 | 15 | 5 |
------------ --------- ----------- ----- -----
Какой самый простой способ сделать это?
Комментарии:
1. Каков ваш путь в сравнении? Возможно, у вас уже есть «самый острый способ» (что бы это ни значило).
2. Мой путь ужасен… Это будет итерация между «01/01/2020» и любой конечной датой, и для каждой повторяемой даты я бы также выполнял итерацию по продукту, и я искал в исходном df строку, которая подходила бы, а затем добавлял к другому фрейму данных. Однако такая итерация в большом фрейме данных, как у меня, просто расплавляет процессор… Кроме того, это совсем не pythonic.
3. Ewww. Звучит по-моему. Можете ли вы добавить это к вопросу, чтобы никому не пришла в голову идея опубликовать это в качестве ответа?
4. Я мог бы также создать функцию для запуска «apply (lambda x; …, axis = 1)», что означает, что она будет выполнять итерацию по каждой строке df, и эта функция будет выбирать даты «От» и «До» и копировать каждую строку для каждой из этих дат. Это было бы более плавно, но я не знаю, смогу ли я добавить к df изнутри лямбда-функции. В любом случае, я думаю, что может быть лучшее решение.
Ответ №1:
Я предполагаю, что столбцы From и Until имеют тип datetime .
Определите следующую функцию для преобразования каждой строки в фрейм данных с этой строкой, «увеличенной» для каждой даты:
def proc(row):
dct = row.loc['Product':'Int'].to_dict()
return pd.DataFrame({'Date': pd.date_range(row.From, row.Until)}).assign(**dct)
Затем примените его к каждой строке и объедините полученный результат:
result = pd.concat(df.apply(proc, axis=1).tolist(), ignore_index=True)
Комментарии:
1. Прекрасный ответ! Прошло много времени с тех пор, как я так много узнал из одного ответа. Мне нравится, как вы применили, а затем tolist() для создания нескольких фреймов данных. Я даже не знал, что это возможно. Спасибо. Этот ответ заслуживает гораздо большей наглядности