【问题标题】:Pandas Dataframe Time Duration Expand to Minute DataPandas Dataframe 持续时间扩展到分钟数据
【发布时间】:2020-11-04 13:11:54
【问题描述】:

我收到的数据包含“开始时间”和“持续时间”的活动时间。当我需要在多天的指定时间范围内进行计算时,这很难处理。我想将这些数据分解为微小的数据,以使未来的计算更容易。请查看示例以获得更好的理解。

我目前拥有的数据:

data = {'StartTime':['2018-12-30 12:45:00+11:00','2018-12-31 16:48:00+11:00','2019-01-01 04:36:00+11:00','2019-01-01 19:27:00+11:00','2019-01-02 05:13:00+11:00'],
        'Duration':[1,1,3,1,2],
        'Site':['1','2','3','4','5']    
}

df = pd.DataFrame(data)
df['StartTime'] = pd.to_datetime(df['StartTime']).dt.tz_localize('utc').dt.tz_convert('Australia/Melbourne')

我想要什么:

data_expected = {'Time':['2018-12-30 12:45:00+11:00','2018-12-31 16:48:00+11:00','2019-01-01 04:36:00+11:00','2019-01-01 04:37:00+11:00','2019-01-01 19:27:00+11:00','2019-01-02 05:13:00+11:00','2019-01-02 05:14:00+11:00'],
        'Duration':[1,1,1,1,1,1,1],
        'Site':['1','2','3','3','4','5','5']    
}

df_expected = pd.DataFrame(data_expected)
df_expected['Time'] = pd.to_datetime(df_expected['Time']).dt.tz_localize('utc').dt.tz_convert('Australia/Melbourne')

我想看看是否有人对此问题有好的解决方案。实际上,对于超过 1 分钟的持续时间,我需要将 Duration >1 的数据行以 +1 分钟的时间复制。有没有办法在不创建全新数据框的情况下做到这一点?

********编辑********

回应@DavidErickson 的回答。把它放在这里是因为我不能把图像放在 cmets 中。我遇到了一些麻烦。 df1 是原始数据帧的子集。 df2 是 df1 应用提供的代码后。您可以看到添加到索引 635 的时间不正确。

【问题讨论】:

  • 这部分代码.dt.tz_localize('utc').dt.tz_convert('Australia/Melbourne') 的语法对我不起作用。您可以使用我的答案并找出语法作为转换到另一个时区的最后一步。
  • 可以持续时间大于2吗?
  • @jlandercy 是的,它可以大于 2
  • @DavidErickson 抱歉,这是我的错误。我将 df_expected 中的列名从“StartTime”更改为“Time”,以尝试突出显示时间数据的变化。我将进行编辑以解决此问题。

标签: python pandas time aggregate duration


【解决方案1】:

我认为您可能还想解决Duration > 2 的用例。

对于修改后的给定输入:

data = {'StartTime':['2018-12-30 12:45:00+11:00','2018-12-31 16:48:00+11:00','2019-01-01 04:36:00+11:00','2019-01-01 19:27:00+11:00','2019-01-02 05:13:00+11:00'],
        'Duration':[1,1,3,1,2],
        'Site':['1','2','3','4','5']    
}

df = pd.DataFrame(data)
df['StartTime'] = pd.to_datetime(df['StartTime'])

这段代码应该可以解决问题:

df['offset'] = df['Duration'].apply(lambda x: list(range(x)))
df = df.explode('offset')
df['offset'] = df['offset'].apply(lambda x: pd.Timedelta(x, unit='T'))
df['StartTime'] += df['offset']
df["Duration"] = 1

基本上,它的工作原理如下:

  • 根据 Duration 值创建整数列表;
  • 使用连续整数偏移量复制行 (explode);
  • 将整数偏移量转换为timedelta偏移量;
  • 执行datetime 算术并重置持续时间字段。

结果大约是:

                  StartTime  Duration Site   offset
0 2018-12-30 12:45:00+11:00         1    1 00:00:00
1 2018-12-31 16:48:00+11:00         1    2 00:00:00
2 2019-01-01 04:36:00+11:00         1    3 00:00:00
2 2019-01-01 04:37:00+11:00         1    3 00:01:00
2 2019-01-01 04:38:00+11:00         1    3 00:02:00
3 2019-01-01 19:27:00+11:00         1    4 00:00:00
4 2019-01-02 05:13:00+11:00         1    5 00:00:00
4 2019-01-02 05:14:00+11:00         1    5 00:01:00

【讨论】:

  • 我收到以下错误:``` AttributeError: 'DataFrame' object has no attribute 'explode' ```
  • @meronpan 您可能使用的是旧版本的熊猫并考虑更新。只有更新版本的 pandas 爆炸了。
  • @meronpan,考虑使用:python -m pip install -U pandas 进行升级。干杯
  • 谢谢大家。这是一个非常烦人的问题,因为您似乎已经为我找到了解决方案,但我的 Pandas 不是最新的。我目前正在使用我的工作电脑,所以升级 Pandas 并不容易。将尝试使其正常工作。干杯
  • @meronpan,然后改用python -m pip install -U --user pandas。绝对升级你的熊猫,你缺少重要的功能。干杯
【解决方案2】:

使用df.index.repeat根据Duration列添加相关行数。然后使用.groupbycumcount 创建一个掩码,在基准时间之上添加适当的分钟数。

输入:

data = {'StartTime':['2018-12-30 12:45:00+11:00','2018-12-31 16:48:00+11:00','2019-01-01 04:36:00+11:00','2019-01-01 19:27:00+11:00','2019-01-02 05:13:00+11:00'],
        'Duration':[1,1,2,1,2],
        'Site':['1','2','3','4','5']    
}
df = pd.DataFrame(data)
df['StartTime'] = pd.to_datetime(df['StartTime'])

代码:

df = df.loc[df.index.repeat(df['Duration'])]
mask = df.groupby('Site').cumcount()
df['StartTime'] = df['StartTime'] + pd.to_timedelta(mask, unit='m')
df = df.append(df).sort_values('StartTime').assign(Duration=1).drop_duplicates()
df

输出:

    StartTime                   Duration    Site
0   2018-12-30 12:45:00+11:00   1           1
1   2018-12-31 16:48:00+11:00   1           2
2   2019-01-01 04:36:00+11:00   1           3
2   2019-01-01 04:37:00+11:00   1           3
2   2019-01-01 04:38:00+11:00   1           3
3   2019-01-01 19:27:00+11:00   1           4
4   2019-01-02 05:13:00+11:00   1           5
4   2019-01-02 05:14:00+11:00   1           5

如果您遇到内存问题,您也可以尝试使用dask。我已经包含了@jlandercy 的pandas 答案并更改为dask 语法,因为我不确定pandas 操作index.repeat 是否适用于dask。这是有关功能/操作的文档。我会研究代码https://docs.dask.org/en/latest/dataframe-api.html#dask.dataframe.read_sql_table中的那些:

import dask.dataframe as dd
#read as a dask dataframe from csv or SQL or other
df = dd.read_csv(files) #df = dd.read_sql_table(table, uri, index_col='StartTime')
df['offset'] = df['Duration'].apply(lambda x: list(range(x)))
df = dd.explode('offset')
df['offset'] = df['offset'].apply(lambda x: dd.Timedelta(x, unit='T'))
df['StartTime'] += df['offset']
df["Duration"] = 1

【讨论】:

  • 我已经向 OP 询问了精度,我们还需要解决 Duration > 2 的用例。
  • 我收到以下错误:ValueError: invalid timedelta unit min provided
  • @meronpan 您必须使用不同的版本。尝试'minute''minutes' 而不是'min'
  • @DavidErickson 感谢 ``` unit='m' ``` 为我工作。不幸的是,这段代码似乎在持续时间> 2 时不起作用。请参考修改后的问题,其中使用了持续时间值 3。
  • 啊,我用另一种方式解释了你的问题。我会努力修改
猜你喜欢
  • 1970-01-01
  • 2021-10-23
  • 1970-01-01
  • 2022-01-01
  • 2017-03-15
  • 2022-01-02
  • 1970-01-01
  • 2020-01-03
  • 1970-01-01
相关资源
最近更新 更多