【问题标题】:How can I count the number of days between a 1 and the next 0如何计算 1 和下一个 0 之间的天数
【发布时间】:2021-02-26 19:30:24
【问题描述】:

[我附上了我的系列图片和获取系列的代码,我如何获得一个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)

【问题讨论】:

  • 欢迎来到 SO!请将数据直接粘贴到问题中并格式化为代码。更容易复制和复制
  • 这不是您的问题,但请查看接受的答案 stackoverflow.com/questions/57431667/… 。 (它计算直到新出现的次数。)

标签: python pandas datetime series timedelta


【解决方案1】:

您可以在这里使用itertool.groupby 之类的 groupby 来尝试此操作。每组的提取第一个索引。由于您必须找到两组之间的差异,因此 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]

【讨论】:

    【解决方案2】:

    我认为像下面这样的东西应该可以工作,首先有一个带有日期索引的系列:

    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,所以我忽略了这些。

    【讨论】:

    • 谢谢它的工作,现在我必须对另一个数据集做同样的事情,但是索引是整数,你知道怎么做吗?
    • 创建索引的时候不加pd.to_datetime()?如果您的索引不重复,它应该可以工作..
    • 当索引为整数时,我得到一个关于填充值需要标量的错误
    • 嗨@VanillaChoco441,如果我没有看到数据,我无法帮助你。我用整数索引尝试了上面的代码并且它有效。而且我怀疑您必须正确构建 pd 系列。另外,由于您是 SO 新手,这有点超出您的问题范围
    • 我希望您对尽最大努力回答您的问题的用户公平,不要通过提出更多超出范围的问题来移动目标职位......或与其他数据集有关本案
    【解决方案3】:

    从创建一个包含 date 列的 DataFrame 开始 dates 转换为 datetimeval 列组成的values

    df = pd.DataFrame({'date': pd.to_datetime(dates), 'val': values})
    

    得到结果的思路是:

    • 获取 val == 0 的日期(对于其他行,取 NaT)。
    • 执行“反向填充”。
    • 减去日期
    • 从上面的结果(timedelta)得到天数。
    • 0 (在您的情况下)填充未完成的 NaT 值(如果有) 这与最后 2 行有关,后面没有任何“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 的行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-26
      • 2010-10-07
      • 1970-01-01
      相关资源
      最近更新 更多