在我下面的代码中,我创建了一个DataFrame df,其中包含包含value和时间戳的示例数据。此外,我还添加了一个新列'value_timespan',并将其初始化为-1。然后,我遍历DataFrame以计算'value'列中连续正值之间的时间跨度。
需要注意两点,第一是即使有多个连续的正值,也只计算连续的正值形成对的时间差,不计算后续的正值不形成对的时间差(见下面的例子)。
第二,在连续的正值之间可以有任意数量的零。
import pandas as pd
from datetime import datetime
# Sample data
data = {
'datetime': [
datetime(2023, 11, 11, 8, 0, 0),
datetime(2023, 11, 11, 8, 5, 0),
datetime(2023, 11, 11, 8, 10, 0),
datetime(2023, 11, 11, 8, 15, 0),
datetime(2023, 11, 11, 8, 20, 0),
datetime(2023, 11, 11, 8, 25, 0),
datetime(2023, 11, 11, 8, 30, 0),
datetime(2023, 11, 11, 8, 35, 0),
datetime(2023, 11, 11, 8, 40, 0),
datetime(2023, 11, 11, 8, 45, 0),
datetime(2023, 11, 11, 8, 50, 0),
],
'value': [1, 3, 4, 2, -1, 1, 0, 2, -3, 0, -3],
}
# Create the DataFrame
df = pd.DataFrame(data)
df['value_timespan'] = -1
# Initialize variables to keep track of the last positive value and its timestamp
last_positive_value = None
last_positive_timestamp = None
# Iterate through the DataFrame
for index, row in df.iterrows():
if row['value'] > 0:
if last_positive_value is not None:
# Calculate the time span between the current positive value and the last positive value
time_difference = (row['datetime'] - last_positive_timestamp).total_seconds()
df.at[index, 'value_timespan'] = time_difference
last_positive_value = None
last_positive_timestamp = None
else:
last_positive_value = row['value']
last_positive_timestamp = row['datetime']
if row['value'] < 0:
last_positive_value = None
last_positive_timestamp = None
print(df)
字符串
它打印出如下结果,(1,3),(4,2),(1,2)被认为是对
datetime | value | value_timespan
--------------------------------------------
0 2023-11-11 08:00:00 | 1 | -1
1 2023-11-11 08:05:00 | 3 | 300
2 2023-11-11 08:10:00 | 4 | -1
3 2023-11-11 08:15:00 | 2 | 300
4 2023-11-11 08:20:00 | -1 | -1
5 2023-11-11 08:25:00 | 1 | -1
6 2023-11-11 08:30:00 | 0 | -1
7 2023-11-11 08:35:00 | 2 | 600
8 2023-11-11 08:40:00 | -3 | -1
9 2023-11-11 08:45:00 | 0 | -1
10 2023-11-11 08:50:00 | -3 | -1
型
现在,我想对我的代码进行矢量化。我如何正确地进行矢量化?
更新2023/12/07
例如,对于'value':[1,3,1,-2,-1,1,0,0,3,0,-3],
正确的结果是,因为(1,3),(1,3)形成一对
datetime | value | timespan
-----------------------------------------
0 2023-11-11 08:00:00 | 1 | -1.0
1 2023-11-11 08:05:00 | 3 | 300.0
2 2023-11-11 08:10:00 | 1 | -1.0
3 2023-11-11 08:15:00 | -2 | -1.0
4 2023-11-11 08:20:00 | -1 | -1.0
5 2023-11-11 08:25:00 | 1 | -1.0
6 2023-11-11 08:30:00 | 0 | -1.0
7 2023-11-11 08:35:00 | 0 | -1.0
8 2023-11-11 08:40:00 | 3 | 900.0
9 2023-11-11 08:45:00 | 0 | -1.0
10 2023-11-11 08:50:00 | -3 | -1.0
型
我希望我的要求是明确的。
2条答案
按热度按时间l2osamch1#
编辑新版本,仅使用
numpy
进行完全矢量化:26 ms,100万行。矢量化解决方案
简洁而快速,在这里。我将在下面提供解释。
字符串
简化设置
为了测试这一点,我们考虑几个设置:
op1
是OP提供的第一个示例,op2
是第二个示例。然后,gen(n)
生成任意大的测试df
。型
测试
型
速度
型
(详细)说明
第一部分是相当习惯的:我们建立连续的非负值组(负值本身属于哪一组并不重要)。我们将使用
op1
作为例子:型
注意前四个值是如何在第1组中组合在一起的,接下来的四个是如何在第2组中组合在一起的(从-1开始)等等。
下一部分是计算这些值中哪些是严格正的。为了可视化索引,我们使用一个小的辅助函数
rix
,它在索引处产生1
,在其他地方产生0
(给出一个完整大小的向量):型
有了这个:
型
从这里开始,我们可以关注
gp = g[ipos]
,即v
为正的组值。现在,一个棘手的部分。我们需要找到
ipos
的每一个奇数索引,但 * 在每个组 * 内。它是每隔一个ipos
,但有时我们必须跳过一个(如果一个组已经改变,我们不能选择第一个)。为了说明这个问题,假设我们有:
型
在这种情况下,我们想要找到第二个
0
(索引1),第二个1
(索引3),以及第二个和第四个2
(索引6,8)。为此,我们设计了一个掩码,其
xor
-累加仅在感兴趣的索引处为1
。这个掩码
z
最初是True
,除了一个组中的第一个元素之外,gp
的所有元素都是True
。为了方便起见,我们在开头添加了一个sentinel-1
:型
我们还跟踪
gp
变化的索引:型
现在,为了纠正
z
,我们将前一组长度为偶数的组中的第一位设置为1
。然后,我们xor
-累加这些位:型
这里就是了,
m
中的是我们想要的索引。所以,总结一下:回到
op1
的例子,ix
是[1, 3, 5]
(相对于ipos
)。最后,在这些位置的时间跨度简单地是
t[ix] - t[ix - 1]
(其中t
是df.iloc[ipos]['t']
)。a11xaf1n2#
我不认为代码可以完全矢量化,因为需要连续的对处理和渐进的回看-这就是为什么你使用最后一个_值。首先注意
itertuples
比iterrows
快,因为Pandas Series不是从每一行形成的。但是最好只在提取的Series上做必要的循环,而不是在DF行上。下面的代码这证明了这一点。这在大约0.5秒内处理了100万行数据,我想这在一个独立的应用程序中已经足够了。字符串
其给出:
型