我如何优化这个在点击流中查找会话持续时间的循环?

How can I optimize this for loop that finds session duration in clickstreams?

我是 Python 数据科学的初学者,我正在做点击流分析。我的文件太大——大约 3300 万行。我是 运行 我制作的用于查找会话持续时间的脚本。我正在打印 i 以查找操作进度。然而,将近 12 个小时过去了,我只达到了 400 000。它有将近 900 万个会话。以这种速度,将需要近 270 小时(11 天)。我需要优化它以减少时间。

这是数据集:

             Sid                    Tstamp     Itemid
0              1  2014-04-07T10:54:09.868Z  214536500
1              1  2014-04-07T10:54:46.998Z  214536506
2              1  2014-04-07T10:57:00.306Z  214577561
3              2  2014-04-07T13:56:37.614Z  214662742
4              2  2014-04-07T13:57:19.373Z  214662742
5              2  2014-04-07T13:58:37.446Z  214825110
6              2  2014-04-07T13:59:50.710Z  214757390
7              2  2014-04-07T14:00:38.247Z  214757407
8              2  2014-04-07T14:02:36.889Z  214551617

这是我的代码。我认为 for 循环正在减慢操作速度。对于会话持续时间,我首先在每个会话中找到最大和最小时间戳。然后在 for 循环中,我将它们转换为 seconds.microseconds,然后在 Tstamp 列中同时更新最终减法。

adi = "H:/excelfiles/clicks3.csv"
k = pandas.read_csv(adi)

k.columns=['Sid','Tstamp','Itemid']

#Dropping Redundant Columns
k.drop(k.columns[2],axis=1,inplace=True)

#Stores max timestamp in amax
idx=k.groupby(['Sid'])['Tstamp'].transform(max) == k['Tstamp']
amax=k[idx].set_index('Sid')

#Stores min timestamp in amin
idy=k.groupby(['Sid'])['Tstamp'].transform(min) == k['Tstamp']
amin=k[idy].set_index('Sid')

i=0
for temp1,temp2,temp3 in zip(amax['Tstamp'],amax.index,amin['Tstamp']):
    sv1= datetime.datetime.strptime(temp1, "%Y-%m-%dT%H:%M:%S.%fZ")
    sv2= datetime.datetime.strptime(temp3, "%Y-%m-%dT%H:%M:%S.%fZ")
    if(i%1000==0):    
        print i
    d1=time.mktime(sv1.timetuple()) + (sv1.microsecond / 1000000.0)
    d2=time.mktime(sv2.timetuple()) + (sv2.microsecond / 1000000.0)
    amax.loc[temp2,'duration']= (d1-d2)/60   
    i=i+1

#amax stores the final session duration
amax=amax.reset_index()

如何优化此代码。

编辑 1:删除了微秒部分。

好的,如果你可以忽略微秒或毫秒部分,你可以试试我的模块 mktime.

安装它

pip install mktime

用法

import mktime
mktime.mktime("2014-04-07T10:54:09.868Z")
# 1396868049

性能测试

% cat test.py
from mktime import mktime
import datetime
import time

temp1 = "2014-04-07T10:54:09.868Z"

def test1():
    sv1 = datetime.datetime.strptime(temp1, "%Y-%m-%dT%H:%M:%S.%fZ")
    d1=time.mktime(sv1.timetuple()) + (sv1.microsecond / 1000000.0)
    #print d1

def test2():
    d1 = mktime(temp1)
    #print d1

结果(100 倍我的机器)

% python -m timeit -s 'import test' 'test.test1()'
10000 loops, best of 3: 20 usec per loop
% python -m timeit -s 'import test' 'test.test2()'
1000000 loops, best of 3: 0.199 usec per loop

如果你有数百万,还没有在内存中分配整个列表,你也可以使用 itertools.izip for 循环。

像这样

from mktime import mktime
from itertools import izip

i = 0
for temp1,temp2,temp3 in izip(amax['Tstamp'],amax.index,amin['Tstamp']):
    if(i%1000==0):    
        print i
    amax.loc[temp2,'duration']= (mktime(temp1) - mktime(temp3)) / 60.0
    i=i+1

这是使用标准 pandas 方法的一种非常简单的方法。您真正需要做的就是将 'Tstamp' 转换为 pandas 日期时间,然后取最大值和最小值的差值。由于它是日期时间,因此差异自动是时间增量。

>>> import pandas as pd

>>> k['Tstamp'] = pd.to_datetime( k['Tstamp'] ) 

>>> duration = ( k.groupby('Sid')['Tstamp'].max() 
               - k.groupby('Sid')['Tstamp'].min() )

Sid
1   00:02:50.438000
2   00:05:59.275000
Name: Tstamp, dtype: timedelta64[ns]