过滤数据以仅获取月份行的第一天

时间:2014-09-11 21:13:05

标签: python-2.7 pandas

我有一个每日数据的数据集。我只需要获取数据集中每个月第一天的数据(数据是从1972年到2013年)。因此,例如,我需要提取索引20,日期2013-12-02值0.1555。 我遇到的问题是每个月的第一天是不同的,所以我不能使用诸如relativedelta(months = 1)之类的步骤,我将如何从我的数据集中提取这些值?

是否有类似于我在R的另一篇文章中找到的命令?    R - XTS: Get the first dates and values for each month from a daily time series with missing rows

17 2013-12-05 0.1621 18 2013-12-04 0.1698 19 2013-12-03 0.1516 20 2013-12-02 0.1555 21 2013-11-29 0.1480 22 2013-11-27 0.1487 23 2013-11-26 0.1648

4 个答案:

答案 0 :(得分:9)

我会按月分组,然后得到每组的第0行(第n行)。

首先设置为索引(我认为这是必要的):

In [11]: df1 = df.set_index('date')

In [12]: df1
Out[12]:
             n     val
date
2013-12-05  17  0.1621
2013-12-04  18  0.1698
2013-12-03  19  0.1516
2013-12-02  20  0.1555
2013-11-29  21  0.1480
2013-11-27  22  0.1487
2013-11-26  23  0.1648

接下来排序,以便第一个元素是该月的第一个日期(注意:这不是出现是第n个必需的,但我认为这实际上是一个错误!):< / p>

In [13]: df1.sort_index(inplace=True)

In [14]: df1.groupby(pd.TimeGrouper('M')).nth(0)
Out[14]:
             n     val
date
2013-11-26  23  0.1648
2013-12-02  20  0.1555

另一种选择是重新取样并获取第一个条目:

In [15]: df1.resample('M', 'first')
Out[15]:
             n     val
date
2013-11-30  23  0.1648
2013-12-31  20  0.1555

考虑到这一点,你可以通过提取月份然后分组来更简单地做到这一点:

In [21]: pd.DatetimeIndex(df.date).to_period('M')
Out[21]:
<class 'pandas.tseries.period.PeriodIndex'>
[2013-12, ..., 2013-11]
Length: 7, Freq: M

In [22]: df.groupby(pd.DatetimeIndex(df.date).to_period('M')).nth(0)
Out[22]:
    n       date     val
0  17 2013-12-05  0.1621
4  21 2013-11-29  0.1480

这次df.date 的排序与(正确)相关,如果您知道它按降序排列,可以使用nth(-1)

In [23]: df.groupby(pd.DatetimeIndex(df.date).to_period('M')).nth(-1)
Out[23]:
    n       date     val
3  20 2013-12-02  0.1555
6  23 2013-11-26  0.1648

如果无法保证,请先按日期栏排序:df.sort('date')

答案 1 :(得分:1)

一种方法是为年,月和日添加一列:

df['year'] = df.SomeDatetimeColumn.map(lambda x: x.year)
df['month'] = df.SomeDatetimeColumn.map(lambda x: x.month)
df['day'] = df.SomeDatetimeColumn.map(lambda x: x.day)

然后按年份和月份进行分组,按天排序,并仅采用第一个条目(这将是最小日期条目)。

df.groupby(
    ['year', 'month']
).apply(lambda x: x.sort('day', ascending=True)).head(1)

使用lambda表达式使其不适合大型数据集。您可能不希望通过保留单独存储的年,月和日值来增加数据的大小。但是,对于这些特殊的日期对齐问题,迟早将这些值分开是非常有帮助的。

另一种方法是直接按日期时间列的功能分组:

dfrm.groupby(
    by=dfrm.dt.map(lambda x: (x.year, x.month))
).apply(lambda x: x.sort('dt', ascending=True).head(1))

通常这些问题是由于数据库或数据存储架构功能失常而导致的,这些架构存在于Python / pandas层之前的一个级别。

例如,在这种情况下,依赖于日历数据库表或日历数据集的存在应该是司空见惯的,该日历数据库表包含(或使其易于查询)相对于该月的最早活动日期。给定数据集(例如,第一个交易日,第一个工作日,第一个工作日,第一个假期或其他)。

如果伴随数据库表存在此数据,则应该很容易将其与已加载的数据集(例如,通过连接您已有的日期列)组合,然后只需应用逻辑过滤日历数据列。

一旦您需要使用日期延迟,这一点变得尤为重要:例如,将公司1个月前的市值与公司当月的股票回报对齐,以计算在该1个月期间实现的总回报

这个可以通过使用shift滞后pandas中的列来完成,或尝试执行可能非常容易出错的复杂自连接并且会产生使特定问题永久化的问题对使用该代码中的数据的下游的每个地方的日期约定。

更好地简单地要求(或自己动手)数据必须以原始格式(数据库,平面文件,等等)正确标准化日期功能并停止正在进行的操作,首先修复该日期问题,并且然后才回过头来对日期数据进行一些分析。

答案 2 :(得分:0)

import pandas as pd
dates = pd.date_range('2014-02-05', '2014-03-15', freq='D') 
df = pd.DataFrame({'vals': range(len(dates))}, index=dates)
g = df.groupby(lambda x: x.strftime('%Y-%m'), axis=0)
g.apply(lambda x: x.index.min())
#Or depending on whether you want the index or the vals
g.apply(lambda x: x.ix[x.index.min()])

答案 3 :(得分:0)

上述内容对我不起作用,因为我每月需要多行,每个月的行数可能会发生变化。这就是我所做的:

dates_month = pd.bdate_range(df['date'].min(), df['date'].max(), freq='1M')
df_mth = df[df['date'].isin(dates_month)]