从其他数据帧创建新的 pandas 时间序列数据帧
Create new pandas timeseries dataframe from other dataframe
如何从一个现有的 df.dataframe 创建一个新的 pandas 时间序列数据框。
假设事件 A 于 11/28 11:35 开始并于 11/29 19:53 结束,这是计数 1。事件 A 第二个实例再次于 11/28 11:37 开始并于 11/ 结束29 19:53 - 计算另一个 1。所以我将 A 的值增加到 2。(抱歉,数据输入错误地是 11/28 而不是 11/29)
源 df 给出了事件的开始和结束时间。并且同一事件可以同时发生多次。
新的 df 应该有给定分钟内事件累计计数的时间序列,范围从最小(开始时间)到最大(结束时间)。
来源 Df:
Start-Time | End-Time | Event
11/28/2014 11:35 | 11/29/2014 19:53 | A
11/28/2014 11:36 | 11/28/2014 11:37 | B
11/28/2014 11:32 | 11/28/2014 19:53 | C
11/28/2014 11:37 | 11/28/2014 19:53 | A
......
新DF:
TimeStamp | A | B | C
11/28/2014 11:35 | 1 | 0 | 1
11/28/2014 11:36 | 1 | 1 | 1
11/28/2014 11:37 | 2 | 1 | 1
.....
11/29/2014 19:53 | 2 | 0 | 1
这有点棘手,因为您希望结束时间算作 "on" 状态,但我认为这样的事情应该可行(警告:考虑到奇怪的边缘情况,我花了零时间,所以买家要当心):
df = pd.melt(df, id_vars="Event", var_name="Which", value_name="Time")
df["Signal"] = df.pop("Which").replace({"Start-Time": 1, "End-Time": -1})
pivoted = df.pivot(columns="Event", index="Time").fillna(0)
pivoted = pivoted.sort_index() # just in case; can't remember if this is guaranteed
df_out = pivoted.cumsum() + (pivoted == -1)
产生
>>> df_out
Signal
Event A B C
Time
11/28/2014 11:32 0 0 1
11/28/2014 11:35 1 0 1
11/28/2014 11:36 1 1 1
11/28/2014 11:37 2 1 1
11/28/2014 19:53 2 0 1
11/29/2014 19:53 1 0 0
基本思路是添加一个带符号的 "Signal" 列并使用它来跟踪更改:
>>> df
Event Time Signal
0 A 11/28/2014 11:35 1
1 B 11/28/2014 11:36 1
2 C 11/28/2014 11:32 1
3 A 11/28/2014 11:37 1
4 A 11/29/2014 19:53 -1
5 B 11/28/2014 11:37 -1
6 C 11/28/2014 19:53 -1
7 A 11/28/2014 19:53 -1
然后我们可以旋转它来获得状态变化:
>>> pivoted
Signal
Event A B C
Time
11/28/2014 11:32 0 0 1
11/28/2014 11:35 1 0 0
11/28/2014 11:36 0 1 0
11/28/2014 11:37 1 -1 0
11/28/2014 19:53 -1 0 -1
11/29/2014 19:53 -1 0 0
并累加得到状态:
>>> pivoted.cumsum()
Signal
Event A B C
Time
11/28/2014 11:32 0 0 1
11/28/2014 11:35 1 0 1
11/28/2014 11:36 1 1 1
11/28/2014 11:37 2 0 1
11/28/2014 19:53 1 0 0
11/29/2014 19:53 0 0 0
这几乎是我们想要的,但您希望包括结束时间,因此我们可以通过撤消关闭来延迟效果:
>>> pivoted.cumsum() + (pivoted == -1)
Signal
Event A B C
Time
11/28/2014 11:32 0 0 1
11/28/2014 11:35 1 0 1
11/28/2014 11:36 1 1 1
11/28/2014 11:37 2 1 1
11/28/2014 19:53 2 0 1
11/29/2014 19:53 1 0 0
这里的方法与@DSM 的方法略有不同。我将 start
和 end
列堆叠在一起,然后在 length
上使用 groupby
和 aggregate
函数进行过滤。然后为了达到想要的输出效果我pivot
table。
start = [35, 36, 37, 36, 35]
end = [56, 56, 56, 58, 58]
events = ['A', 'B', 'C', 'A', 'A']
df = pd.DataFrame( {'start': start, 'end': end, 'events': events})
# stack the 'start' and 'end' columns here
new_df = pd.DataFrame({ 'times': df['start'].append(df['end']), 'events': df['events'].append(df['events']) })
new_df = new_df.groupby(['times', 'events']).agg(len)
# massage the data frame to conform to desired output
new_df = new_df.reset_index().pivot('times', 'events').fillna(0)
连接后的数据框如下所示:
events times
0 A 35
1 B 36
2 C 37
3 A 36
4 A 35
0 A 56
1 B 56
2 C 56
3 A 58
4 A 58
groupby
分组后的数据框:
times events
35 A 2
36 A 1
B 1
37 C 1
56 A 1
B 1
C 1
58 A 2
最后是枢轴后的数据框:
events A B C
times
35 2 0 0
36 1 1 0
37 0 0 1
56 1 1 1
58 2 0 0
我认为@DSM 的解决方案在计算时间方面比我的解决方案更有效,因为 append
方法相当昂贵,因为它需要在每次调用时构建一个全新的对象。我还没有对这两种方法进行计时,所以我不确定。
如何从一个现有的 df.dataframe 创建一个新的 pandas 时间序列数据框。
假设事件 A 于 11/28 11:35 开始并于 11/29 19:53 结束,这是计数 1。事件 A 第二个实例再次于 11/28 11:37 开始并于 11/ 结束29 19:53 - 计算另一个 1。所以我将 A 的值增加到 2。(抱歉,数据输入错误地是 11/28 而不是 11/29)
源 df 给出了事件的开始和结束时间。并且同一事件可以同时发生多次。 新的 df 应该有给定分钟内事件累计计数的时间序列,范围从最小(开始时间)到最大(结束时间)。
来源 Df:
Start-Time | End-Time | Event
11/28/2014 11:35 | 11/29/2014 19:53 | A
11/28/2014 11:36 | 11/28/2014 11:37 | B
11/28/2014 11:32 | 11/28/2014 19:53 | C
11/28/2014 11:37 | 11/28/2014 19:53 | A
......
新DF:
TimeStamp | A | B | C
11/28/2014 11:35 | 1 | 0 | 1
11/28/2014 11:36 | 1 | 1 | 1
11/28/2014 11:37 | 2 | 1 | 1
.....
11/29/2014 19:53 | 2 | 0 | 1
这有点棘手,因为您希望结束时间算作 "on" 状态,但我认为这样的事情应该可行(警告:考虑到奇怪的边缘情况,我花了零时间,所以买家要当心):
df = pd.melt(df, id_vars="Event", var_name="Which", value_name="Time")
df["Signal"] = df.pop("Which").replace({"Start-Time": 1, "End-Time": -1})
pivoted = df.pivot(columns="Event", index="Time").fillna(0)
pivoted = pivoted.sort_index() # just in case; can't remember if this is guaranteed
df_out = pivoted.cumsum() + (pivoted == -1)
产生
>>> df_out
Signal
Event A B C
Time
11/28/2014 11:32 0 0 1
11/28/2014 11:35 1 0 1
11/28/2014 11:36 1 1 1
11/28/2014 11:37 2 1 1
11/28/2014 19:53 2 0 1
11/29/2014 19:53 1 0 0
基本思路是添加一个带符号的 "Signal" 列并使用它来跟踪更改:
>>> df
Event Time Signal
0 A 11/28/2014 11:35 1
1 B 11/28/2014 11:36 1
2 C 11/28/2014 11:32 1
3 A 11/28/2014 11:37 1
4 A 11/29/2014 19:53 -1
5 B 11/28/2014 11:37 -1
6 C 11/28/2014 19:53 -1
7 A 11/28/2014 19:53 -1
然后我们可以旋转它来获得状态变化:
>>> pivoted
Signal
Event A B C
Time
11/28/2014 11:32 0 0 1
11/28/2014 11:35 1 0 0
11/28/2014 11:36 0 1 0
11/28/2014 11:37 1 -1 0
11/28/2014 19:53 -1 0 -1
11/29/2014 19:53 -1 0 0
并累加得到状态:
>>> pivoted.cumsum()
Signal
Event A B C
Time
11/28/2014 11:32 0 0 1
11/28/2014 11:35 1 0 1
11/28/2014 11:36 1 1 1
11/28/2014 11:37 2 0 1
11/28/2014 19:53 1 0 0
11/29/2014 19:53 0 0 0
这几乎是我们想要的,但您希望包括结束时间,因此我们可以通过撤消关闭来延迟效果:
>>> pivoted.cumsum() + (pivoted == -1)
Signal
Event A B C
Time
11/28/2014 11:32 0 0 1
11/28/2014 11:35 1 0 1
11/28/2014 11:36 1 1 1
11/28/2014 11:37 2 1 1
11/28/2014 19:53 2 0 1
11/29/2014 19:53 1 0 0
这里的方法与@DSM 的方法略有不同。我将 start
和 end
列堆叠在一起,然后在 length
上使用 groupby
和 aggregate
函数进行过滤。然后为了达到想要的输出效果我pivot
table。
start = [35, 36, 37, 36, 35]
end = [56, 56, 56, 58, 58]
events = ['A', 'B', 'C', 'A', 'A']
df = pd.DataFrame( {'start': start, 'end': end, 'events': events})
# stack the 'start' and 'end' columns here
new_df = pd.DataFrame({ 'times': df['start'].append(df['end']), 'events': df['events'].append(df['events']) })
new_df = new_df.groupby(['times', 'events']).agg(len)
# massage the data frame to conform to desired output
new_df = new_df.reset_index().pivot('times', 'events').fillna(0)
连接后的数据框如下所示:
events times
0 A 35
1 B 36
2 C 37
3 A 36
4 A 35
0 A 56
1 B 56
2 C 56
3 A 58
4 A 58
groupby
分组后的数据框:
times events
35 A 2
36 A 1
B 1
37 C 1
56 A 1
B 1
C 1
58 A 2
最后是枢轴后的数据框:
events A B C
times
35 2 0 0
36 1 1 0
37 0 0 1
56 1 1 1
58 2 0 0
我认为@DSM 的解决方案在计算时间方面比我的解决方案更有效,因为 append
方法相当昂贵,因为它需要在每次调用时构建一个全新的对象。我还没有对这两种方法进行计时,所以我不确定。