如果在某些时间/值之间,熊猫累积总和

Posted

技术标签:

【中文标题】如果在某些时间/值之间,熊猫累积总和【英文标题】:Pandas cumulative sum if between certain times/values 【发布时间】:2020-10-02 06:46:35 【问题描述】:

我想在final_df 中插入一个名为total 的新列,这是dfvalue 的累积总和,如果它发生在final_df 中的时间之间。如果它出现在final_df 中的startend 之间,它将对这些值求和。例如,在 final_df 的 01:30 到 02:00 时间范围内 - df 中的索引 0 和 1 都出现在此时间范围内,因此总数为 15 (10+5)。

我有两个熊猫数据框:

df

import pandas as pd

d = 'start_time': ['01:00','00:00','00:30','02:00'], 
     'end_time': ['02:00','03:00','01:30','02:30'], 
     'value': ['10','5','20','5']

df = pd.DataFrame(data=d)

final_df

final_df = 'start_time': ['00:00, 00:30, 01:00, 01:30, 02:00, 02:30'],
            'end_time': ['00:30, 01:00, 01:30, 02:00, 02:30, 03:00']

final_df = pd.DataFrame(data=final_d)

我想要的输出 final_df

start_time  end_time total
00:00       00:30    5
00:30       01:00    25
01:00       01:30    35
01:30       02:00    15
02:30       03:00    10

我的尝试

final_df['total'] = final_df.apply(lambda x: df.loc[(df['start_time'] >= x.start_time) & 
                                            (df['end_time'] <= x.end_time), 'value'].sum(), axis=1)

问题 1

我收到错误:TypeError: ("'>=' not supported between 'str' and 'datetime.time'", 'occured at index 0')

我将相关列转换为日期时间如下:

df[['start_time','end_time']] = df[['start_time','end_time']].apply(pd.to_datetime, format='%H:%M')
final_df[['start_time','end_time']] = final_df[['start_time','end_time']].apply(pd.to_datetime, format='%H:%M:%S')

但我不想转换为日期时间。有没有办法解决这个问题?

问题 2

总和工作不正常。它只在时间范围内寻找完全匹配。所以输出是:

 start_time  end_time total
    00:00       00:30    0
    00:30       01:00    0
    01:00       01:30    0
    01:30       02:00    0
    02:30       03:00    5

【问题讨论】:

【参考方案1】:

不使用apply 的一种方法可能是这样。

df_ = (df.rename(columns='start_time':1, 'end_time':-1) #to use in the calculation later
         .rename_axis(columns='mult') # mostly for esthetic
         .set_index('value').stack() #reshape the data
         .reset_index(name='time') # put the index back to columns
      )
df_ = (df_.set_index(pd.to_datetime(df_['time'], format='%H:%M')) #to use resampling technic
          .assign(total=lambda x: x['value'].astype(float)*x['mult']) #get plus or minus the value depending start/end
          .resample('30T')[['total']].sum() # get the sum at the 30min bounds
          .cumsum() #cumulative sum from the beginning
      )
# create the column for merge with final resul
df_['start_time'] = df_.index.strftime('%H:%M')

# merge
final_df = final_df.merge(df_)

你得到

print (final_df)
  start_time end_time  total
0      00:00    00:30    5.0
1      00:30    01:00   25.0
2      01:00    01:30   35.0
3      01:30    02:00   15.0
4      02:00    02:30   10.0
5      02:30    03:00    5.0

但如果你想使用 apply,首先你需要确保列是好的 dtype,然后你按照相反的顺序做了不公平,比如:

df['start_time'] = pd.to_datetime(df['start_time'], format='%H:%M')
df['end_time'] = pd.to_datetime(df['end_time'], format='%H:%M')
df['value'] = df['value'].astype(float)
final_df['start_time'] = pd.to_datetime(final_df['start_time'], format='%H:%M')
final_df['end_time'] = pd.to_datetime(final_df['end_time'], format='%H:%M')

final_df.apply(
    lambda x: df.loc[(df['start_time'] <= x.start_time) & #see other inequality
                     (df['end_time'] >= x.end_time), 'value'].sum(), axis=1)
0     5.0
1    25.0
2    35.0
3    15.0
4    10.0
5     5.0
dtype: float64

【讨论】:

不错的答案@Ben.T. 很好的答案,两种解决方案都有效。对于应用解决方案,由于某种原因,我的 final_df 中的最后一个时间范围(即 23:30 到 00:00。注意不包括我上面的示例)汇总了列中不应该出现的所有内容。 @thor hmm like this 我不知道为什么,我会尝试测试一些东西,但是是的,边界效应是可能的,尤其是在播放间隔时:) @thor 所以在考虑了一下你的评论之后,你得到所有的总和是有道理的,像这样我不确定是否有一个简单的解决方法。如果你用这个间隔写出不等式,那么你得到 (df['start_time'] = 00:00) 这确实给出了 df 中的所有值。跨度>

以上是关于如果在某些时间/值之间,熊猫累积总和的主要内容,如果未能解决你的问题,请参考以下文章

熊猫按时间和分组滚动条件总和

选择具有累积总和的两个日期之间的日期和值

如何在熊猫数据框中执行不同值的累积和

SQL Server - 重叠数据的累积总和 - 获取总和达到给定值的日期

累积和 - 选择层次结构的部分

SQL 计算基于 Hive 列中先前值重置的累积总和