【问题标题】:Convert pandas df with data in a "list column" into a time series in long format. Use three columns: [list of data] + [timestamp] + [duration]将带有“列表列”中数据的 pandas df 转换为长格式的时间序列。使用三列:[数据列表] + [时间戳] + [持续时间]
【发布时间】:2020-11-24 13:16:32
【问题描述】:

目的是将列表列作为数据列(因此每行只有一个时间戳和持续时间)的数据帧转换为长格式的时间序列,每个单项都有一个datetimeindex

在结果中,每行数据不再有序列/列表,而只有一个value 列。

df_test = pd.DataFrame({'timestamp': [1462352000000000000, 1462352100000000000, 1462352200000000000, 1462352300000000000],
                        'list': [[1,2,1,9], [2,2,3,0], [1,3,3,0], [1,1,3,9]],
                        'duration_sec': [3.0, 3.0, 3.0, 3.0]})

tdi = pd.DatetimeIndex(df_test.timestamp)
df_test.set_index(tdi, inplace=True)
df_test.drop(columns='timestamp', inplace=True)
df_test.index.name = 'datetimeindex'

输出:

                       list          duration_sec
datetimeindex                                      
2016-05-04 08:53:20  [1, 2, 1, 9]           3.0
2016-05-04 08:55:00  [2, 2, 3, 0]           3.0
2016-05-04 08:56:40  [1, 3, 3, 0]           3.0
2016-05-04 08:58:20  [1, 1, 3, 9]           3.0

目标是:

                   value
datetimeindex
2016-05-04 08:53:20  1
2016-05-04 08:53:21  2
2016-05-04 08:53:22  1
2016-05-04 08:53:23  9
2016-05-04 08:55:00  2
2016-05-04 08:55:01  2
2016-05-04 08:55:02  3
2016-05-04 08:55:03  0
2016-05-04 08:56:40  1
2016-05-04 08:56:41  3
2016-05-04 08:56:42  3
2016-05-04 08:56:43  0
2016-05-04 08:58:20  1
2016-05-04 08:58:21  1
2016-05-04 08:58:22  3
2016-05-04 08:58:23  9

请注意,这不仅意味着每个项目要花 1 秒时间;这只是为了简化示例。相反,它是一个序列中的大约 4 个项目,具有给定的持续时间,例如 3.0 秒(也可能因行而异),并且每个序列的第一个项目总是从“时间 0”开始,这意味着每个项目的秒数应该像这样计算

[3.0 秒 / (4-1) 项] = 1 秒。

上下文:

该示例显示转换为Datetimeindex,因为这使其适用于seasonal_decompose(),请参阅this 第一次搜索命中。

在那里,生成的 df 如下所示:

df_test2 = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'], index_col='date')

输出:

                value
date                 
1991-07-01   3.526591
1991-08-01   3.180891
1991-09-01   3.252221
1991-10-01   3.611003
1991-11-01   3.565869
              ...
2008-02-01  21.654285
2008-03-01  18.264945
2008-04-01  23.107677
2008-05-01  22.912510
2008-06-01  19.431740

[204 rows x 1 columns]

然后很容易通过additive分解模型应用seasonal_decompose()

result_add = seasonal_decompose(df_test2['value'], model='additive', extrapolate_trend='freq')

# Plot
plt.rcParams.update({'figure.figsize': (5,5)})
result_add.plot().suptitle('Additive Decompose', fontsize=22)
plt.show()

现在上面的df_test 也需要这样。

【问题讨论】:

  • duration_sec 列在这个问题中有什么意义吗?
  • @EddyG 它是必需的,因为您需要以某种方式找出“开始”之后的下一个时间戳,对于每一行您只知道一次。我没有关于每个序列中项目之间时间的任何其他信息。因此,我认为下一个时间戳只能通过“+duration / len(sequence)”来计算。

标签: pandas dataframe timestamp nested-lists datetimeindex


【解决方案1】:

先使用DataFrame.explode,然后将GroupBy.cumcountto_timedelta的计数器添加到df.index

df_test = df_test.explode('nestedList')
df_test.index += pd.to_timedelta(df_test.groupby(level=0).cumcount(), unit='s')

print (df_test)
                    nestedList  duration_sec
2016-05-04 08:53:20          1           3.0
2016-05-04 08:53:21          2           3.0
2016-05-04 08:53:22          1           3.0
2016-05-04 08:53:23          9           3.0
2016-05-04 08:55:00          2           3.0
2016-05-04 08:55:01          2           3.0
2016-05-04 08:55:02          3           3.0
2016-05-04 08:55:03          0           3.0
2016-05-04 08:56:40          1           3.0
2016-05-04 08:56:41          3           3.0
2016-05-04 08:56:42          3           3.0
2016-05-04 08:56:43          0           3.0
2016-05-04 08:58:20          1           3.0
2016-05-04 08:58:21          1           3.0
2016-05-04 08:58:22          3           3.0
2016-05-04 08:58:23          9           3.0

编辑:

df_test = df_test.explode('nestedList') 
sizes = df_test.groupby(level=0)['nestedList'].transform('size').sub(1)
duration = df_test['duration_sec'].div(sizes) 
df_test.index += pd.to_timedelta(df_test.groupby(level=0).cumcount() * duration, unit='s') 

提问者的 EDIT2:

有了生成的 df,decompose() 的这个简单应用现在成为可能,这是最终目标:

result_add = seasonal_decompose(x=df_test['nestedList'], model='additive', extrapolate_trend='freq', period=int(len(df_test)/2))
plt.rcParams.update({'figure.figsize': (5,5)})
result_add.plot().suptitle('Additive Decompose', fontsize=22)
plt.show()

【讨论】:

  • 至于@EddyG 的评论,目前这只是数秒。如果我在序列中有 50 个项目,并且持续时间为 30 秒,那么这将不再有效。我必须为每个计数添加 30/50 秒而不是一整秒。我现在接受这个太早了,我的问题并不清楚。尽管关于问题发布的几分钟,现在的答案已经很精彩了。
  • @Lorenz - 我不清楚一件事,子列表中有 4 个值,但有 duration_sec 列除以 3 ?所以这意味着默认情况下是通过1 减去长度?那么解决方案是df_test = df_test.explode('nestedList')sizes = df_test.groupby(level=0)['nestedList'].transform('size').sub(1).div(df_test['duration_sec'])df_test.index += pd.to_timedelta(df_test.groupby(level=0).cumcount() * sizes, unit='s')
  • 我将更改问题,以便持续时间不再计算角色,而是按每个项目通常设置的持续时间,无论它可能是什么顺序。给我几分钟。
  • 好的,完成了,现在问题中包含了全局持续时间变量。请在您的答案中使用groupby(level=0).cumcount() * sizes 更改您的想法到groupby(level=0).cumcount() * duration,在之前引入duration = 1,然后删除输出中现在不需要的duration_sec 列。谢谢
  • 我会检查的。如果这解决了它,我会告诉你,它可能有助于推导出你现在似乎提供的每件物品的持续时间。看起来很有希望,给我一些时间。
猜你喜欢
  • 2013-06-07
  • 2018-04-02
  • 2023-03-23
  • 2019-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-26
  • 2018-11-30
相关资源
最近更新 更多