2015-03-31 44 views
61

sto creando un dataframe da un file CSV come segue:selezionare le righe dataframe tra due date

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

Il dataframe ha una colonna di data. C'è un modo per creare un nuovo dataframe (o semplicemente sovrascrivere quello esistente) che contiene solo righe che rientrano in un intervallo di date specifico?

risposta

146

ci sono due soluzioni possibili:

  • usare una maschera booleana, quindi utilizzare df.loc[mask]
  • impostare la colonna data come un DatetimeIndex, quindi utilizzare df[start_date : end_date]

Utilizzando un maschera booleana:

Garantire df['date'] è una serie con DTYPE datetime64[ns]:

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

fare una maschera booleano. start_date e end_date può essere datetime.datetime s, np.datetime64 s, pd.Timestamp s, o stringhe persino datetime:

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

selezionare il sub-dataframe:

df.loc[mask] 

o ri-assegnare a df

df = df.loc[mask] 

.515.053.691,36321 milioni

Per esempio,

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]) 

cede

  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 

Utilizzando un DatetimeIndex:

Se avete intenzione di fare un sacco di selezioni per data, può essere più veloce per impostare la colonna date come prima dell'indice. Quindi è possibile selezionare le righe per data utilizzando df.loc[start_date:end_date].

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') 
df = df.set_index(['date']) 
print(df.loc['2000-6-1':'2000-6-10']) 

cede

    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 

Mentre elenco pitone indicizzazione, ad esempio seq[start:end] include start ma non end, al contrario, Panda df.loc[start_date : end_date] include entrambi punti finali nel risultato se si trovano nell'indice. Né start_dateend_date devono tuttavia essere inclusi nell'indice.


Si noti inoltre che pd.read_csv has a parse_dates parameter che si potrebbe usare per analizzare la colonna date come datetime64 s. Pertanto, se si utilizza parse_dates, non è necessario utilizzare df['date'] = pd.to_datetime(df['date']).

+0

Il secondo avvertenza per DatetimeIndex non appare t o essere più vero. – derNincompoop

+0

@derNincompoop: Grazie per la correzione. – unutbu

15

Mi sento l'opzione migliore sarà quella di utilizzare i controlli diretti piuttosto che utilizzare la funzione loc:

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

Funziona per me.

Il problema principale con la funzione di localizzazione con una sezione è che i limiti devono essere presenti nei valori effettivi, altrimenti questo determinerà KeyError.

11

È possibile utilizzare il metodo isin sulla colonna date in questo modo df[df["date"].isin(pd.date_range(start_date, end_date))]

Esempio:

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 

che 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 
1

Nel caso in cui, se avete intenzione di fare questa spesso la soluzione migliore sarebbe quella di iniziare la colonna della data come indice che convertirà la colonna in DateTimeIndex e utilizzerà la seguente condizione per tagliare qualsiasi intervallo di 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')] 
0

Preferisco non modificare lo df.

Una possibilità è quella di recuperare il index delle date start e 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] 

che si traduce in:

 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 
0

È inoltre possibile utilizzare between:

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