दो तिथियों के बीच DataFrame पंक्तियों का चयन करें


196

मैं एक csv से एक DataFrame बना रहा हूँ इस प्रकार है:

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

DataFrame में एक दिनांक स्तंभ होता है। क्या एक नया डेटाफ़्रेम बनाने का एक तरीका है (या सिर्फ मौजूदा को अधिलेखित करें) जिसमें केवल दिनांक मान वाले पंक्तियाँ होती हैं जो किसी निर्दिष्ट दिनांक सीमा के भीतर या दो निर्दिष्ट दिनांक मानों के बीच होती हैं?

जवाबों:


400

दो संभावित उपाय हैं:

  • बूलियन मास्क का उपयोग करें, फिर उपयोग करें df.loc[mask]
  • डेट कॉलम को डेटाइमइंडेक्स के रूप में सेट करें, फिर उपयोग करें df[start_date : end_date]

बूलियन मास्क का उपयोग करना :

सुनिश्चित करें df['date']कि dtype के साथ एक श्रृंखला है datetime64[ns]:

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

बूलियन मास्क बनाएं। start_dateऔर end_dateहो सकता है datetime.datetimeरों, np.datetime64रों, pd.Timestampरों, या यहाँ तक datetime तार:

#greater than the start date and smaller than the end date
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

डेटाटाइम का उपयोग करना :

यदि आप तिथि के अनुसार बहुत सारे चयन करने जा रहे हैं, तो dateपहले कॉलम को इंडेक्स के रूप में सेट करना जल्दी हो सकता है । फिर आप तारीखों का उपयोग करके पंक्तियों का चयन कर सकते हैं 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'])

पैदावार

                   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

जबकि पायथन सूची अनुक्रमण, उदाहरण के लिए seq[start:end]शामिल है, startलेकिन endइसके विपरीत, पंडों के परिणाम में दोनों अंत बिंदु df.loc[start_date : end_date]शामिल हैं अगर वे सूचकांक में हैं। न तो है और न ही हालांकि सूचकांक में हो गया है।start_dateend_date


यह भी ध्यान दें कि pd.read_csvएक parse_datesपैरामीटर है जिसे आप dateकॉलम को पार्स करने के लिए उपयोग कर सकते हैं datetime64। इस प्रकार, यदि आप उपयोग करते हैं, तो आपको उपयोग parse_datesकरने की आवश्यकता नहीं होगी df['date'] = pd.to_datetime(df['date'])


दिनांक कॉलम को सेट करना क्योंकि इंडेक्स अच्छा काम करता है, लेकिन मैंने जो दस्तावेज़ देखा है, उससे यह स्पष्ट नहीं है कि कोई ऐसा कर सकता है। धन्यवाद।
फहीम मीठा

@FaheemMitha: मैंने ऊपर एक लिंक जोड़ा है जहाँ "आंशिक स्ट्रिंग अनुक्रमण" को प्रलेखित किया गया है।
अनटु

वह हिस्सा जो शायद कम स्पष्ट है कि एक सूचकांक को स्पष्ट रूप से बनाया जाना है। और इंडेक्स को स्पष्ट रूप से बनाए बिना, एक प्रतिबंधित सीमा एक खाली सेट लौटाती है, त्रुटि नहीं।
फहीम मीठा

8
df = df.set_index(['date'])चरण के बाद , मैंने पाया है कि सूचकांक को भी क्रमबद्ध (के माध्यम से df.sort_index(inplace=True, ascending=True)) करने की आवश्यकता है , अन्यथा आप पूर्ण या कम से कम डेटाफ़्रेम परिणामों से कम प्राप्त कर सकते हैं df.loc['2000-6-1':'2000-6-10']। और अगर आप उपयोग करते हैं ascending=False, तो यह बिल्कुल भी काम नहीं करेगा, भले ही आप इसेdf.loc['2000-6-10':'2000-6-1']
bgoodr

यदि आप 'डेट' कॉलम को अभी भी रखना चाहते हैं, तो इसके मूल्य को डेटाफ्रेम के सूचकांक में दे सकते हैं, तो आप यह df.index = df ['तारीख'] कर सकते हैं
रिचर्ड लियांग

64

मुझे लगता है कि सबसे अच्छा विकल्प लोकल फंक्शन का उपयोग करने के बजाय सीधे चेक का उपयोग करना होगा:

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

इससे मेरा काम बनता है।

स्लाइस के साथ लोक फ़ंक्शन के साथ प्रमुख मुद्दा यह है कि सीमाएं वास्तविक मूल्यों में मौजूद होनी चाहिए, यदि ऐसा नहीं होगा तो इसके परिणामस्वरूप KeyError होगा।


मुझे लगता है कि स्लाइस के माध्यम locसे महान हैं। और यह मुझे लगता है कि जैसा कि अनटुब कहते हैं, न तो start_date और न ही end_date को हालांकि इंडेक्स में होना चाहिए
nealmcb

दिनांक को फ़िल्टर कैसे करें (वर्तमान तिथि तक 14 दिन पहले) .. यदि आज की तारीख 2019-01-15 है ... मुझे (2019-01-01
प्रवीण

सरल और सुरुचिपूर्ण। धन्यवाद क्रिस्टीन, यह वही है जो मैं करने की कोशिश कर रहा था। मेरे लिये कार्य करता है।
ब्रजियो

35

आप यह भी उपयोग कर सकते हैं between:

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

2
यह भी देखें between_time: pandas.pydata.org/pandas-docs/version/0.20.3/generated/…
एंटोन

@AntonTarasenko अजीब, साथ काम नहीं करता datetimes केवल, बल्कि कई बार । इस भेद को महसूस करने में मुझे कुछ समय लगा। इस तरह मैंने इस धागे से सलाह ली।
रॉटन

19

आप isinइस dateतरह से कॉलम पर विधि का उपयोग कर सकते हैं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

9

समाधान को सरल और पायथोनिक रखते हुए, मैं आपको यह कोशिश करने का सुझाव दूंगा।

यदि आप अक्सर ऐसा करने जा रहे हैं, तो सबसे अच्छा समाधान यह होगा कि आप सबसे पहले डेट कॉलम को इंडेक्स के रूप में सेट करें, जो डेटाइमइंडेक्स में कॉलम को रूपांतरित करेगा और किसी भी श्रेणी के दिनांक को स्लाइस करने के लिए निम्न स्थिति का उपयोग करेगा।

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

4

pandasसंस्करण के मेरे परीक्षण के साथ 0.22.0अब आप केवल उपयोग करके अधिक पठनीय कोड के साथ इस प्रश्न का आसान उत्तर दे सकते हैं between

# 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')})

मान लीजिए कि आप 27 नवंबर 2018 से 15 जनवरी 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

समावेशी तर्क पर ध्यान दें। बहुत उपयोगी है जब आप अपनी सीमा के बारे में स्पष्ट होना चाहते हैं। सूचना जब हम सच में सेट करते हैं तो हम २०१ we के नवंबर २ we को लौटेंगे:

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

यह विधि पहले बताई गई isinविधि से भी तेज है :

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

हालांकि, यह वर्तमान में स्वीकार किए गए उत्तर की तुलना में तेज नहीं है , अनटुब द्वारा प्रदान किया गया है, केवल अगर मुखौटा पहले से ही बनाया गया है । लेकिन अगर मुखौटा गतिशील है और उसे बार-बार आश्वस्त करने की आवश्यकता है, तो मेरा तरीका अधिक कुशल हो सकता है:

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

3

मैं पसंद नहीं बदलने के लिए 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

3

एक अन्य विकल्प, इसे कैसे प्राप्त किया जाए, यह pandas.DataFrame.query()विधि का उपयोग करके है। मुझे आपको निम्नलिखित डेटा फ़्रेम पर एक उदाहरण दिखाते हैं df

>>> df = pd.DataFrame(np.random.random((5, 1)), columns=['col_1'])
>>> df['date'] = pd.date_range('2020-1-1', periods=5, freq='D')
>>> print(df)
      col_1       date
0  0.015198 2020-01-01
1  0.638600 2020-01-02
2  0.348485 2020-01-03
3  0.247583 2020-01-04
4  0.581835 2020-01-05

एक तर्क के रूप में, इस तरह से छानने के लिए स्थिति का उपयोग करें:

>>> start_date, end_date = '2020-01-02', '2020-01-04'
>>> print(df.query('date >= @start_date and date <= @end_date'))
      col_1       date
1  0.244104 2020-01-02
2  0.374775 2020-01-03
3  0.510053 2020-01-04

यदि आप सीमाओं को शामिल नहीं करना चाहते हैं, तो बस निम्नलिखित जैसी स्थिति बदलें:

>>> print(df.query('date > @start_date and date < @end_date'))
      col_1       date
2  0.374775 2020-01-03
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.