Панды создают строки на основе интервала между датами

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

Для этого я в настоящее время использую метод, который в основном создает декартово произведение, которое хорошо работает с небольшими наборами данных, но не подходит для больших наборов, потому что оно очень неэффективно.

Этот метод будет использоваться для ~ 2 миллионов строк на 50 столбцов Dataframe, охватывающих несколько лет от минимальной до максимальной даты. В результирующем наборе данных будет около 3 миллионов строк, поэтому требуется более эффективный подход.

Мне не удалось найти альтернативный метод, менее ресурсоемкий. Что было бы лучшим подходом для этого?

Мой текущий метод здесь:

from datetime import date
import pandas as pd

raw_data = {'id': ['aa0', 'aa1', 'aa2', 'aa3'],
'number': [1, 2, 2, 1],
'color': ['blue', 'red', 'yellow', "green"],
'date_start': [date(2022,1,1), date(2022,1,1), date(2022,1,7), date(2022,1,12)],
'date_end': [date(2022,1,2), date(2022,1,4), date(2022,1,9), date(2022,1,14)]}


df = pd.DataFrame(raw_data)

Это дает следующий результат Панды создают строки на основе интервала между датами

Теперь, чтобы создать набор, содержащий все возможные даты между минимальной и максимальной датой набора:

df_d = pd.DataFrame({'date': pd.date_range(df['date_start'].min(), df['date_end'].max() + pd.Timedelta('1d'), freq='1d')})

Это приводит к ожидаемому кадру, содержащему все возможные даты.

Панды создают строки на основе интервала между датами

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

df_total = pd.merge(df, df_d,how='cross')
df = df_total[(df_total['date_start']<df_total['date']) & (df_total['date_end']>=df_total['date']) ]

Это приводит к следующему окончательному Панды создают строки на основе интервала между датами

Этот окончательный фрейм данных — именно то, что нужно.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Эффективное решение

d = df['date_end'].sub(df['date_start']).dt.days
df1 = df.reindex(df.index.repeat(d))
i = df1.groupby(level=0).cumcount() + 1

df1['date'] = df1['date_start'] + pd.to_timedelta(i, unit='d')

Как это устроено?

Вычтите начало из конца, чтобы рассчитать количество прошедших дней, затем reindex фрейм данных, повторив индекс точное количество прошедших дней. Теперь сгруппируйте df1 по index и используйте cumcount, чтобы создать последовательный счетчик, затем создайте серию timedelta, используя этот счетчик, и добавьте это с date_start, чтобы получить результат.

Результат

    id  number   color  date_start    date_end        date
0  aa0       1    blue  2022-01-01  2022-01-02  2022-01-02
1  aa1       2     red  2022-01-01  2022-01-04  2022-01-02
1  aa1       2     red  2022-01-01  2022-01-04  2022-01-03
1  aa1       2     red  2022-01-01  2022-01-04  2022-01-04
2  aa2       2  yellow  2022-01-07  2022-01-09  2022-01-08
2  aa2       2  yellow  2022-01-07  2022-01-09  2022-01-09
3  aa3       1   green  2022-01-12  2022-01-14  2022-01-13
3  aa3       1   green  2022-01-12  2022-01-14  2022-01-14

Я не знаю, является ли это утверждением, здесь pd.date_range создается только для каждой даты начала и окончания в каждой строке. созданный список взорвется и соединится с исходным df

from datetime import date
import pandas as pd

raw_data = {'id': ['aa0', 'aa1', 'aa2', 'aa3'],
'number': [1, 2, 2, 1],
'color': ['blue', 'red', 'yellow', "green"],
'date_start': [date(2022,1,1), date(2022,1,1), date(2022,1,7), date(2022,1,12)],
'date_end': [date(2022,1,2), date(2022,1,4), date(2022,1,9), date(2022,1,14)]}


df = pd.DataFrame(raw_data)

s = df.apply(lambda x: pd.date_range(x['date_start'], x['date_end'], freq='1d',inclusive='right').date,axis=1).explode()
df.join(s.rename('date'))

Другие вопросы по теме