Ik maak een DataFrame van een csv als volgt:
stock = pd.read_csv('data_in/' + filename + '.csv', skipinitialspace=True)
De DataFrame heeft een datum kolom. Is er een manier om een nieuw DataFrame te maken (of gewoon het bestaande DataFrame te overschrijven) dat alleen rijen bevat met datumwaarden die binnen een gespecificeerd datumbereik vallen of tussen twee gespecificeerde datumwaarden?
Er zijn twee mogelijke oplossingen:
df.loc[masker]
df[start_date : end_date]
Gebruik een boolean mask:
Zorg ervoor dat df['date']
een Serie is met dtype datetime64[ns]
:
df['date'] = pd.to_datetime(df['date'])
Maak een booleaans masker. start_datum
en eind_datum
kunnen datetime.datetime
s zijn,
np.datetime64
s, pd.Timestamp
s, of zelfs datetime strings:
#greater than the start date and smaller than the end date
mask = (df['date'] > start_date) & (df['date'] <= end_date)
Selecteer het sub-DataFrame:
df.loc[mask]
of wijs het toe aan df
df = df.loc[mask]
Bijvoorbeeld,
importeer numpy als np
importeer pandas als pd
df = pd.DataFrame(np.random.random((200,3))
df['date'] = pd.date_range('2000-1-1', periods=200, freq='D')
mask = (df['datum'] > '2000-6-1') & (df['datum'] <= '2000-6-10')
print(df.loc[mask])
geeft
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
Gebruik makend van een DatetimeIndex:
Als je veel selecties op datum gaat doen, kan het sneller zijn om eerst de
datum
kolom als index in te stellen. Dan kunt u rijen op datum selecteren met
df.loc[start_date:end_date]
.
importeer numpy als np
importeer pandas als pd
df = pd.DataFrame(np.random.random((200,3))
df['date'] = pd.date_range('2000-1-1', periods=200, freq='D')
df = df.set_index(['datum'])
print(df.loc['2000-6-1':'2000-6-10'])
geeft
0 1 2
date
2000-06-01 0.040457 0.326594 0.492136 # <- includes start_date
2000-06-02 0.279323 0.877446 0.464523
2000-06-03 0.328068 0.837669 0.608559
2000-06-04 0.107959 0.678297 0.517435
2000-06-05 0.131555 0.418380 0.025725
2000-06-06 0.999961 0.619517 0.206108
2000-06-07 0.129270 0.024533 0.154769
2000-06-08 0.441010 0.741781 0.470402
2000-06-09 0.682101 0.375660 0.009916
2000-06-10 0.754488 0.352293 0.339337
Terwijl Python lijst indexering, bijv. seq[start:end]
start
meeneemt maar niet eind
, neemt Pandas df.loc[start_date : end_date]
daarentegen beide eindpunten mee in het resultaat als ze in de index staan. Noch start_datum
noch eind_datum
hoeven echter in de index te staan.
Merk ook op dat pd.read_csv
een parse_dates
parameter heeft die je zou kunnen gebruiken om de datum
kolom te parsen als datetime64
s. Dus, als je parse_dates
gebruikt, zou je niet df['date'] = pd.to_datetime(df['date'])
hoeven te gebruiken.
Ik denk dat de beste optie zal zijn om de directe controles te gebruiken in plaats van de loc-functie:
df = df[(df['date'] > '2000-6-1') & (df['date'] <= '2000-6-10')]
Het werkt voor mij.
Groot probleem met loc functie met een slice is dat de grenzen aanwezig moeten zijn in de werkelijke waarden, zo niet zal dit resulteren in KeyError.
U kunt de isin
methode gebruiken op de datum
kolom als volgt
df[df["date"].isin(pd.date_range(start_date, end_date))]
Note: Dit werkt alleen met datums (zoals de vraag vraagt) en niet met timestamps.
Voorbeeld:
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
dat geeft
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