Python 如何计算从1到下一个0之间的天数

Python 如何计算从1到下一个0之间的天数,python,pandas,datetime,series,timedelta,Python,Pandas,Datetime,Series,Timedelta,[我已附上我系列的图片和获取系列的代码,如何获取1和下一个0之间的天数。例如,第一个1和下一个0之间的天数为4天(8月1日至8月5日),下一个1和0之间的天数也为4天[8月8日至8月12日] 我认为下面的方法应该有效,首先是一个带有日期索引的系列: ds = pd.Series(values, index = pd.to_datetime(dates)) 然后计算连续值之间的差值: delta = ds - ds.shift(fill_value=ds[0]-1) 看起来是这样的: pd.D

[我已附上我系列的图片和获取系列的代码,如何获取1和下一个0之间的天数。例如,第一个1和下一个0之间的天数为4天(8月1日至8月5日),下一个1和0之间的天数也为4天[8月8日至8月12日]


我认为下面的方法应该有效,首先是一个带有日期索引的系列:

ds = pd.Series(values, index = pd.to_datetime(dates))
然后计算连续值之间的差值:

delta = ds - ds.shift(fill_value=ds[0]-1)
看起来是这样的:

pd.DataFrame({'value':ds,'delta':delta})


    value   delta
2019-08-01  1   1
2019-08-02  1   0
2019-08-05  0   -1
2019-08-06  0   0
2019-08-07  0   0
2019-08-08  1   1
2019-08-09  1   0
2019-08-12  0   -1
2019-08-13  1   1
2019-08-14  0   -1
因此,您需要的开始日期是delta为1时,下一个零是-1时。因此:

starts = ds.index[delta == 1]
ends = ds.index[delta == -1]
(ends - starts[:len(ends)]).days

Int64Index([4, 4, 1, 7], dtype='int64')

请注意,在某些情况下,在数据帧的末尾,您有1个,但它们没有转换为0,因此我忽略了这些。您可以使用groupby(如
itertool.groupby)在此处尝试此操作。提取每个组的第一个索引。由于您必须找到两个组之间的差异,因此如果为n,则必须有相同数量的1组和0组对案例进行分析,然后删除最后一组

s = pd.Series(values, index = pd.to_datetime(dates))
g = s.ne(s.shift()).cumsum()
vals = s.groupby(g).apply(lambda x:x.index[0])
# vals
1    2019-08-01
2    2019-08-05
3    2019-08-08
4    2019-08-12
5    2019-08-13
6    2019-08-14
7    2019-08-16
8    2019-08-23
9    2019-08-29
dtype: object
现在我们没有相同数量的1组和0组,所以丢弃组索引。并将块大小设为2,即现在,每个块都有1和0组索引

end = None if not len(vals)%2 else -1
vals = vals.iloc[:end].values.reshape((-1, 2))
# vals 
array([['2019-08-01T00:00:00.000000000', '2019-08-05T00:00:00.000000000'],
       ['2019-08-08T00:00:00.000000000', '2019-08-12T00:00:00.000000000'],
       ['2019-08-13T00:00:00.000000000', '2019-08-14T00:00:00.000000000'],
       ['2019-08-16T00:00:00.000000000', '2019-08-23T00:00:00.000000000']],
      dtype='datetime64[ns]')
现在,我们必须使用
np.diff
找到差异

days = np.diff(vals, axis=1).squeeze()
out = pd.Series(days)
# out

0   4 days
1   4 days
2   1 days
3   7 days
dtype: timedelta64[ns]

从创建数据框开始,日期列由 转换为datetime和val列的日期由以下值组成:

获得结果的想法是:

         date  val  dist
0  2019-08-01    1     4
1  2019-08-02    1     3
2  2019-08-05    0     0
3  2019-08-06    0     0
4  2019-08-07    0     0
5  2019-08-08    1     4
6  2019-08-09    1     3
7  2019-08-12    0     0
8  2019-08-13    1     1
9  2019-08-14    0     0
10 2019-08-15    0     0
11 2019-08-16    1     7
12 2019-08-19    1     4
13 2019-08-20    1     3
14 2019-08-21    1     2
15 2019-08-22    1     1
16 2019-08-23    0     0
17 2019-08-26    0     0
18 2019-08-27    0     0
19 2019-08-28    0     0
20 2019-08-29    1     0
21 2019-08-30    1     0
  • 获取val==0的日期(对于其他行,使用NaT)
  • 执行“向后填充”
  • 减去日期
  • 从上面的结果(timedelta)得到天数
  • 将未完成的NaT值(如果有)填入0(在您的情况下 这涉及最后两行,后面没有任何“0行”)
  • 将结果保存在dist列中
执行此操作的代码是:

df['dist'] = (df.date.where(df.val == 0).bfill(0) - df.date)\
    .dt.days.fillna(0, downcast='infer')
结果是:

         date  val  dist
0  2019-08-01    1     4
1  2019-08-02    1     3
2  2019-08-05    0     0
3  2019-08-06    0     0
4  2019-08-07    0     0
5  2019-08-08    1     4
6  2019-08-09    1     3
7  2019-08-12    0     0
8  2019-08-13    1     1
9  2019-08-14    0     0
10 2019-08-15    0     0
11 2019-08-16    1     7
12 2019-08-19    1     4
13 2019-08-20    1     3
14 2019-08-21    1     2
15 2019-08-22    1     1
16 2019-08-23    0     0
17 2019-08-26    0     0
18 2019-08-27    0     0
19 2019-08-28    0     0
20 2019-08-29    1     0
21 2019-08-30    1     0
(dist列是以天为单位的距离)


如果需要,请仅从上面的结果中选取val!=0的行。

欢迎使用SO!请将数据直接粘贴到问题中,并将其格式化为代码。更易于复制。这不是您的问题,但请查看已接受的答案。(它计算在新出现之前的数量。)感谢它的工作,现在我不得不对另一个数据集做同样的事情,但是如果索引是整数,你知道怎么做吗?当你创建索引时,你不需要将
pd.to_datetime()
?如果您的索引不重复,它应该可以工作。当索引为intergershi@VanillaChoco441时,我得到一个关于填充值需要为标量的错误。如果我看不到数据,我无法帮助您。我在上面用整数索引尝试了我的代码,它工作了。我怀疑您必须正确构造pd系列。还有ce您是新来的,所以,这有点超出了您的问题范围。我希望您对尽最大努力回答您问题的用户公平,不要通过提出更多超出范围的问题来转移目标帖子……或者在这种情况下与另一个数据集有关的问题
         date  val  dist
0  2019-08-01    1     4
1  2019-08-02    1     3
2  2019-08-05    0     0
3  2019-08-06    0     0
4  2019-08-07    0     0
5  2019-08-08    1     4
6  2019-08-09    1     3
7  2019-08-12    0     0
8  2019-08-13    1     1
9  2019-08-14    0     0
10 2019-08-15    0     0
11 2019-08-16    1     7
12 2019-08-19    1     4
13 2019-08-20    1     3
14 2019-08-21    1     2
15 2019-08-22    1     1
16 2019-08-23    0     0
17 2019-08-26    0     0
18 2019-08-27    0     0
19 2019-08-28    0     0
20 2019-08-29    1     0
21 2019-08-30    1     0