Eu voi crea un DataFrame dintr-un fișier csv, după cum urmează:
stock = pd.read_csv('data_in/' + filename + '.csv', skipinitialspace=True)
DataFrame are o data de coloană. Există o modalitate de a crea un nou DataFrame (sau doar suprascrie unul existent), care conține doar rânduri cu valorile de dată care se încadrează într-un interval de timp specificat sau între două date specificate valori?
Există două soluții posibile:
df.loc[masca]
df[start_date : end_date]
Folosind un boolean masca:
Asigura df['data']
este o Serie cu dtype datetime64[ns]
:
df['date'] = pd.to_datetime(df['date'])
Face un boolean masca. start_date " și " end_date
poate fi `datetime.datetime e,
np.datetime64 e, pd.Timestamp, sau chiar datetime siruri de caractere:
#greater than the start date and smaller than the end date
mask = (df['date'] > start_date) & (df['date'] <= end_date)
Selectați sub-DataFrame:
df.loc[mask]
sau re-atribui "df"
df = df.loc[mask]
De exemplu, `` python import numpy ca np import panda ca pd
df = pd.DataFrame(np.aleatoare.aleatoare((200,3))) df['data'] = pd.date_range('2000-1-1', perioadele=200, freq='D') masca = (df['data'] > '2000-6-1') & (df['data'] <= '2000-6-10') print(df.loc[masca]) `` randamentele
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
Folosind un DatetimeIndex:
Dacă aveți de gând să faceți o mulțime de selecții de data, aceasta poate fi mai rapid pentru a seta
"data" coloană ca și indexul în primul rând. Apoi, puteți selecta rânduri de data folosind
df.loc[start_date:end_date]
.
`` python import numpy ca np import panda ca pd
df = pd.DataFrame(np.aleatoare.aleatoare((200,3))) df['data'] = pd.date_range('2000-1-1', perioadele=200, freq='D') df = df.set_index(['data']) print(df.loc['2000-6-1':'2000-6-10']) ``
randamentele
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
În timp ce Python lista de indexare, de exemplu, urm[start:end]include "start", dar nu "sfârșitul", în contrast, Panda
df.loc[start_date : end_date]include *ambele* end-puncte în rezultat, dacă acestea sunt în index. Nici
start_date", nici " end_date` trebuie să fie în index cu toate acestea.
De asemenea, rețineți că pd.read_csv
are o parse_dates
parametru care le-ar putea folosi pentru a analiza coloana "data" ca datetime64 lui. Astfel, dacă utilizați
parse_dates, tu nu ar trebui să folosească
df['data'] = pd.to_datetime(df['data'])`.
Mă simt cea mai bună opțiune va fi de a folosi direct controale, mai degrabă decât folosind loc funcția:
df = df[(df['date'] > '2000-6-1') & (df['date'] <= '2000-6-10')]
Acesta funcționează pentru mine.
Problema majoră cu funcție de loc cu o felie este ca limitele ar trebui să fie prezente în valori reale, dacă nu acest lucru va duce la KeyError.
Puteți utiliza isin
metoda pe coloana "data" ca asa
df[df["data"].isin(pd.date_range(start_date, end_date))]
Notă: Aceasta funcționează numai cu datele (precum întrebarea cere) și nu marcajele de timp.
Exemplu:
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
care dă
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
Păstrarea soluție simplă și pythonic, aș sugera să încercați acest lucru.
În cazul în care aveți de gând pentru a face acest lucru în mod frecvent cea mai bună soluție ar fi să-și primul set la data de coloană ca și indexul care va converti coloană în DateTimeIndex și de a folosi următoarele stare să taie orice interval de date.
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')]
Prefer să nu modifice "df".
O opțiune este de a prelua "index" a "start" și " end " date:
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]
care duce la:
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
Cu testarea mea de panda
versiune 0.22.0
acum puteți răspunde la această întrebare mai ușoară, cu mai lizibil codul de simplu, folosind intre
.
# create a single column DataFrame with dates going from Jan 1st 2018 to Jan 1st 2019
df = pd.DataFrame({'dates':pd.date_range('2018-01-01','2019-01-01')})
Las's spui că vrei să apuca de date între 27 Noiembrie 2018 și 15 ianuarie 2019:
# use the between statement to get a boolean mask
df['dates'].between('2018-11-27','2019-01-15', inclusive=False)
0 False
1 False
2 False
3 False
4 False
# you can pass this boolean mask straight to loc
df.loc[df['dates'].between('2018-11-27','2019-01-15', inclusive=False)]
dates
331 2018-11-28
332 2018-11-29
333 2018-11-30
334 2018-12-01
335 2018-12-02
Observa inclusive argument. foarte util atunci când doriți să fie explicit despre gama. notificare când este setat la True vom reveni Nov 27 2018 precum:
df.loc[df['dates'].between('2018-11-27','2019-01-15', inclusive=True)]
dates
330 2018-11-27
331 2018-11-28
332 2018-11-29
333 2018-11-30
334 2018-12-01
Această metodă este, de asemenea, mai rapid decât cele menționate anterior isin
metoda:
%%timeit -n 5
df.loc[df['dates'].between('2018-11-27','2019-01-15', inclusive=True)]
868 µs ± 164 µs per loop (mean ± std. dev. of 7 runs, 5 loops each)
%%timeit -n 5
df.loc[df['dates'].isin(pd.date_range('2018-01-01','2019-01-01'))]
1.53 ms ± 305 µs per loop (mean ± std. dev. of 7 runs, 5 loops each)
Cu toate acestea, este nu mai repede decât în prezent răspunsul acceptat, cu condiția de unutbu, numai în cazul în care masca este deja create. dar dacă masca este dinamic și are nevoie să fie redistribuit de peste si peste, metoda mea poate fi mai eficient:
# already create the mask THEN time the function
start_date = dt.datetime(2018,11,27)
end_date = dt.datetime(2019,1,15)
mask = (df['dates'] > start_date) & (df['dates'] <= end_date)
%%timeit -n 5
df.loc[mask]
191 µs ± 28.5 µs per loop (mean ± std. dev. of 7 runs, 5 loops each)