Выбор строк фрейма данных между двумя датами


Я создаю фрейм данных из csv следующим образом:

stock = pd.read_csv('data_in/' + filename + '.csv', skipinitialspace=True)

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

6 92

6 ответов:

есть два возможных решения:

  • используйте логическую маску, затем используйте df.loc[mask]
  • установите столбец даты в качестве DatetimeIndex, затем используйте df[start_date : end_date]

используя логическую маску:

обеспечить df['date'] - это серия с dtype datetime64[ns]:

df['date'] = pd.to_datetime(df['date'])  

сделать логическую маску. start_date и end_date может быть datetime.datetimes, np.datetime64 s,pd.Timestamps, или даже datetime строки:

mask = (df['date'] > start_date) & (df['date'] <= end_date)

выберите суб-фрейм данных:

df.loc[mask]

или повторно назначить df

df = df.loc[mask]

например,

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.random((200,3)))
df['date'] = pd.date_range('2000-1-1', periods=200, freq='D')
mask = (df['date'] > '2000-6-1') & (df['date'] <= '2000-6-10')
print(df.loc[mask])

доходность

            0         1         2       date
153  0.208875  0.727656  0.037787 2000-06-02
154  0.750800  0.776498  0.237716 2000-06-03
155  0.812008  0.127338  0.397240 2000-06-04
156  0.639937  0.207359  0.533527 2000-06-05
157  0.416998  0.845658  0.872826 2000-06-06
158  0.440069  0.338690  0.847545 2000-06-07
159  0.202354  0.624833  0.740254 2000-06-08
160  0.465746  0.080888  0.155452 2000-06-09
161  0.858232  0.190321  0.432574 2000-06-10

используя DatetimeIndex:

если вы собираетесь сделать много выборов по дате, это может быть быстрее, чтобы установить

Я чувствую, что лучшим вариантом будет использовать прямые проверки, а не использовать функцию loc:

df = df[(df['date'] > '2000-6-1') & (df['date'] <= '2000-6-10')]

это работает для меня.

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

можно использовать isin метод вот так df[df["date"].isin(pd.date_range(start_date, end_date))]

Примечание: это работает только с датами (как вопрос), а не метки.

пример:

import numpy as np   
import pandas as pd

# Make a DataFrame with dates and random numbers
df = pd.DataFrame(np.random.random((30, 3)))
df['date'] = pd.date_range('2017-1-1', periods=30, freq='D')

# Select the rows between two dates
in_range_df = df[df["date"].isin(pd.date_range("2017-01-15", "2017-01-20"))]

print(in_range_df)  # print result

что дает

           0         1         2       date
14  0.960974  0.144271  0.839593 2017-01-15
15  0.814376  0.723757  0.047840 2017-01-16
16  0.911854  0.123130  0.120995 2017-01-17
17  0.505804  0.416935  0.928514 2017-01-18
18  0.204869  0.708258  0.170792 2017-01-19
19  0.014389  0.214510  0.045201 2017-01-20

вы также можете использовать between:

df[df.some_date.between(start_date, end_date)]

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

import pandas as pd

data_frame = data_frame.set_index('date')

df = data_frame[(data_frame.index > '2017-08-10') & (data_frame.index <= '2017-08-15')]

Я предпочитаю не изменять df.

опция для получения index на start и end сроки:

import numpy as np   
import pandas as pd

#Dummy DataFrame
df = pd.DataFrame(np.random.random((30, 3)))
df['date'] = pd.date_range('2017-1-1', periods=30, freq='D')

#Get the index of the start and end dates respectively
start = df[df['date']=='2017-01-07'].index[0]
end = df[df['date']=='2017-01-14'].index[0]

#Show the sliced df (from 2017-01-07 to 2017-01-14)
df.loc[start:end]

что приводит к:

     0   1   2       date
6  0.5 0.8 0.8 2017-01-07
7  0.0 0.7 0.3 2017-01-08
8  0.8 0.9 0.0 2017-01-09
9  0.0 0.2 1.0 2017-01-10
10 0.6 0.1 0.9 2017-01-11
11 0.5 0.3 0.9 2017-01-12
12 0.5 0.4 0.3 2017-01-13
13 0.4 0.9 0.9 2017-01-14