如何计算 1 和下一个 0 之间的天数
How can I count the number of days between a 1 and the next 0
[我附上了我的系列图片和获取系列的代码,我如何获得一个1和下一个0之间的天数。例如,第一个1之间的天数而下一个0是4天(8月1日到8月5日),下一个1和0之间的天数也是4天[8月8日到8月12日1
values = [1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]
dates =['2019-08-01', '2019-08-02', '2019-08-05', '2019-08-06',
'2019-08-07', '2019-08-08', '2019-08-09', '2019-08-12',
'2019-08-13', '2019-08-14', '2019-08-15', '2019-08-16',
'2019-08-19', '2019-08-20', '2019-08-21', '2019-08-22',
'2019-08-23', '2019-08-26', '2019-08-27', '2019-08-28',
'2019-08-29', '2019-08-30']
pd.Series(values, index = dates)
我认为像下面这样的东西应该有用,首先有一个带有日期索引的系列:
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,所以我忽略这些。
您可以像 itertool.groupby
一样在此处使用 groupby 进行尝试。提取每组的第一个索引。由于您必须找到差异 b/w 两组,因此 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]
从创建一个包含 date 列的 DataFrame 开始
dates 转换为 datetime 和由 values 组成的 val 列:
df = pd.DataFrame({'date': pd.to_datetime(dates), 'val': values})
得到结果的思路是:
- 获取 val == 0 的日期(对于其他行采用 NaT)。
- 执行“向后填充”。
- 减去日期.
- 从上面的结果 (timedelta) 得到天数。
- 用 0 填充未完成的 NaT 值(如果有)(在您的情况下
这与最后两行有关,后面没有任何“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.
的行
[我附上了我的系列图片和获取系列的代码,我如何获得一个1和下一个0之间的天数。例如,第一个1之间的天数而下一个0是4天(8月1日到8月5日),下一个1和0之间的天数也是4天[8月8日到8月12日1
values = [1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]
dates =['2019-08-01', '2019-08-02', '2019-08-05', '2019-08-06',
'2019-08-07', '2019-08-08', '2019-08-09', '2019-08-12',
'2019-08-13', '2019-08-14', '2019-08-15', '2019-08-16',
'2019-08-19', '2019-08-20', '2019-08-21', '2019-08-22',
'2019-08-23', '2019-08-26', '2019-08-27', '2019-08-28',
'2019-08-29', '2019-08-30']
pd.Series(values, index = dates)
我认为像下面这样的东西应该有用,首先有一个带有日期索引的系列:
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,所以我忽略这些。
您可以像 itertool.groupby
一样在此处使用 groupby 进行尝试。提取每组的第一个索引。由于您必须找到差异 b/w 两组,因此 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]
从创建一个包含 date 列的 DataFrame 开始 dates 转换为 datetime 和由 values 组成的 val 列:
df = pd.DataFrame({'date': pd.to_datetime(dates), 'val': values})
得到结果的思路是:
- 获取 val == 0 的日期(对于其他行采用 NaT)。
- 执行“向后填充”。
- 减去日期.
- 从上面的结果 (timedelta) 得到天数。
- 用 0 填充未完成的 NaT 值(如果有)(在您的情况下 这与最后两行有关,后面没有任何“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.
的行