Python Pandas DataFrame для возврата всех наборов дат в пределах одного месяца - PullRequest
0 голосов
/ 21 октября 2019

У меня есть таблица, подобная приведенной ниже, в качестве ввода:

enter image description here

Который был создан с помощью следующего кода:

import pandas as pd
dates = ['3-Apr-2018', '4-Apr-2018', '15-Apr-2018', '5-May-2018', '3-Jun-2018']
prices = [300, 200, 100, 900, 200]
list_of_tuples = list(zip(dates, prices))
df = pd.DataFrame(list_of_tuples, columns=['dates', 'prices'])

Мне нужны все наборы индексов дат, которые попадают в диапазон за один месяц или 31 день. Вывод этого должен быть:

 [0, 1, 2], [2, 3], [3, 4] 

Ответы [ 2 ]

1 голос
/ 21 октября 2019

Конечно, есть более оптимальное решение, но вот мое предложение:

import pandas as pd

dates = ['3-Apr-2018', '4-Apr-2018', '15-Apr-2018', '5-May-2018', '3-Jun-2018']
prices = [300, 200, 100, 900, 200]
list_of_tuples = list(zip(dates, prices))
df = pd.DataFrame(list_of_tuples, columns=['dates', 'prices'])

#solution:
df['dates'] = pd.to_datetime(df['dates'])

for index, r in df.iterrows():
    df['c_' + str(index)] =  (df['dates'] - r['dates']).apply(lambda x: 1 if pd.Timedelta(0, unit='d')< x <pd.Timedelta(32, unit='d') else 0)
df['m'] = df.groupby(df['dates'].dt.month).ngroup()

d31 = [df.index[df[col] == 1].tolist() for col in df if col.startswith('c_') and df[col].sum() > 1]
months = [*(df.groupby(df['dates'].dt.month).groups.values())]
months = [m.to_list() for m in months]

d31_months = d31 + months

Выход немного отличается от вашего, но я не понимаю, почему не включайте [3], [4] в течение нескольких месяцев:

[[1, 2], [2, 3], [0, 1, 2], [3], [4]]

Мне удалось его немного реорганизовать:

months = [list(m) for m in df.groupby(df['dates'].dt.month).indices.values()]

diff = lambda r: (df['dates'] - r['dates']).apply(lambda x: 1 if pd.Timedelta(0, unit='d') < x < pd.Timedelta(32, unit='d') else 0)
d31 = [list(np.nonzero(df.index[diff(r)])[0]) for i, r in df.iterrows() if diff(r).sum() > 1]

d31_months = d31 + months
1 голос
/ 21 октября 2019

Ниже приведено решение… добавлено несколько дополнительных шагов, чтобы было легче следовать.

  1. Обязательно всегда конвертировать строки в даты
  2. Добавить столбец start_date
  3. Добавить столбец end_date
  4. Написать цикл for, который зацикливаетсячерез каждые start_date и end_date проверять весь столбец
  5. Сохранять результаты во временном списке, который добавляется в основной список результатов
  6. Добавить основной список результатов в новый столбец

# Step 1: make sure to convert the dates
df['dates'] = pd.to_datetime(df['dates'])

# Step 2: create start_date
df['start_date'] = pd.to_datetime(df['dates'])

# Step 3: create end_date column that projects date forward 31 days
df['end_date'] = df['dates'] + pd.Timedelta(days=31)

# create master list to store results of search
list_column_index = []

# loop through each row in dataframe, start_date and end_date
for each_start, each_end in zip(df['start_date'], df['end_date']):

    # compare the entire 'dates' column to the start_date and end_date in this row
    mask_range = df['dates'].between(each_start, each_end)

    # create a new temporary dataframe with dates in this range
    temp_df = df.loc[mask_range]

    # convert the index of the temporary dataframe into a temp_list
    temp_list_index = list(temp_df.index)

    # add the temp list to the master list
    list_column_index.append(temp_list_index)

# add a new column with the master list
df['column_index'] = list_column_index

print(df)
df

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...