我正在尝试从Pandas DataFrame中获取具有连续日期的数据块。我的df
如下所示。
DateAnalyzed Val
1 2018-03-18 0.470253
2 2018-03-19 0.470253
3 2018-03-20 0.470253
4 2018-09-25 0.467729
5 2018-09-26 0.467729
6 2018-09-27 0.467729
在此df
中,我要获取前3行,进行一些处理,然后获取后3行,并对此进行处理。
我通过应用以下代码以1滞后计算出差异。
df['Delta']=(df['DateAnalyzed'] - df['DateAnalyzed'].shift(1))
但是在那之后,我无法弄清楚如何在不进行迭代的情况下获取连续行的组。
答案 0 :(得分:3)
您似乎需要两个布尔掩码:一个用于确定组之间的间隔,另一个用于确定哪个日期在组中。
还有一个棘手的部分可以通过示例来充实。请注意,下面的df
包含一个添加的行,该行之前或之后没有任何连续的日期。
>>> df
DateAnalyzed Val
1 2018-03-18 0.470253
2 2018-03-19 0.470253
3 2018-03-20 0.470253
4 2017-01-20 0.485949 # < watch out for this
5 2018-09-25 0.467729
6 2018-09-26 0.467729
7 2018-09-27 0.467729
>>> df.dtypes
DateAnalyzed datetime64[ns]
Val float64
dtype: object
以下答案假定您要完全忽略2017-01-20
,而不进行处理。 (如果您确实想处理该日期,请参阅答案的结尾以获取解决方案。)
第一:
>>> dt = df['DateAnalyzed']
>>> day = pd.Timedelta('1d')
>>> in_block = ((dt - dt.shift(-1)).abs() == day) | (dt.diff() == day)
>>> in_block
1 True
2 True
3 True
4 False
5 True
6 True
7 True
Name: DateAnalyzed, dtype: bool
现在,in_block
会告诉您哪些日期在“连续”块中,但不会告诉您每个日期属于哪个组。
下一步是推导分组本身:
>>> filt = df.loc[in_block]
>>> breaks = filt['DateAnalyzed'].diff() != day
>>> groups = breaks.cumsum()
>>> groups
1 1
2 1
3 1
5 2
6 2
7 2
Name: DateAnalyzed, dtype: int64
然后,您可以通过选择的操作呼叫df.groupby(groups)
。
>>> for _, frame in filt.groupby(groups):
... print(frame, end='\n\n')
...
DateAnalyzed Val
1 2018-03-18 0.470253
2 2018-03-19 0.470253
3 2018-03-20 0.470253
DateAnalyzed Val
5 2018-09-25 0.467729
6 2018-09-26 0.467729
7 2018-09-27 0.467729
要将其合并回df
中,请分配给它,隔离的日期将为NaN
:
>>> df['groups'] = groups
>>> df
DateAnalyzed Val groups
1 2018-03-18 0.470253 1.0
2 2018-03-19 0.470253 1.0
3 2018-03-20 0.470253 1.0
4 2017-01-20 0.485949 NaN
5 2018-09-25 0.467729 2.0
6 2018-09-26 0.467729 2.0
7 2018-09-27 0.467729 2.0
如果您确实想包含“孤独”日期,事情会变得更加简单:
dt = df['DateAnalyzed']
day = pd.Timedelta('1d')
in_block = ((dt - dt.shift(-1)).abs() == day) | (dt.diff() == day)
breaks = dt.diff() != day
groups = breaks.cumsum()
答案 1 :(得分:0)
在此here和here之后,存在类似的问题,但对输出的要求更为具体。由于这是更笼统的内容,因此我也想在这里做贡献。
我们可以使用一行代码轻松为连续的组分配唯一标识符:
df['grp_date'] = df.DateAnalyzed.diff().dt.days.ne(1).cumsum()
在这里,每次看到相差大于一天的日期时,我们都会向该日期添加一个值,否则它会保留先前的值,从而使每个组都有唯一的标识符。
查看输出:
DateAnalyzed Val grp_date
1 2018-03-18 0.470253 1
2 2018-03-19 0.470253 1
3 2018-03-20 0.470253 1
4 2018-09-25 0.467729 2
5 2018-09-26 0.467729 2
6 2018-09-27 0.467729 2
现在,groupby
“ grp_date”很容易,并且可以使用apply
或agg
做您想做的事情。
示例:
# Sum across consecutive days (or any other method from pandas groupby)
df.groupby('grp_date').sum()
# Get the first value and last value per consecutive days
df.groupby('grp_date').apply(lambda x: x.iloc[[0, -1]])
# or df.groupby('grp_date').head(n) for first n days
# Perform custom operation across target-columns
df.groupby('grp_date').apply(lambda x: (x['col1'] + x['col2']) / x['Val'].mean())
# Multiple operations for a target-column
df.groupby('grp_date').Val.agg(['min', 'max', 'mean', 'std'])
# and so on...