我想通过大型二维数组 (15,100m) 进行一些特征丰富。
处理包含 100,000 条记录的示例集表明我需要更快地完成此操作。
编辑(数据模型信息)
为简化起见,假设我们只有两个相关列:
我想添加第 3 列,计算该 IP 在过去 12 小时内出现的次数。
结束编辑
我的第一次尝试是使用 pandas,因为它很适合使用命名维度,但速度太慢:
for index,row in tqdm_notebook(myData.iterrows(),desc='iterrows'):
# how many times was the IP address (and specific device) around in the prior 5h?
hours = 12
seen = myData[(myData['ip']==row['ip'])
&(myData['device']==row['device'])
&(myData['os']==row['os'])
&(myData['unix']<row['unix'])
&(myData['unix']>(row['unix']-(60*60*hours)))].shape[0]
ip_seen = myData[(myData['ip']==row['ip'])
&(myData['unix']<row['unix'])
&(myData['unix']>(row['unix']-(60*60*hours)))].shape[0]
myData.loc[index,'seen'] = seen
myData.loc[index,'ip_seen'] = ip_seen
然后我切换到 numpy 数组并希望得到更好的结果,但它仍然太慢无法针对完整数据集运行:
# speed test numpy arrays
for i in np.arange(myArray.shape[0]):
hours = 12
ip,device,os,ts = myArray[i,[0,3,4,12]]
ip_seen = myArray[(np.where((myArray[:,0]==ip)
& (myArray[:,12]<ts)
& (myArray[:,12]>(ts-60*60*hours) )))].shape[0]
device_seen = myArray[(np.where((myArray[:,0]==ip)
& (myArray[:,2] == device)
& (myArray[:,3] == os)
& (myArray[:,12]<ts)
& (myArray[:,12]>(ts-60*60*hours) )))].shape[0]
myArray[i,13]=ip_seen
myArray[i,14]=device_seen
我的下一个想法是只迭代一次,并维护一个不断增长的当前计数字典,而不是在每次迭代时都向后看。
但这会有一些其他缺点(例如,如何跟踪何时减少超出 12 小时窗口的观测值的计数)。
您将如何解决这个问题?
甚至可以选择使用低级 Tensorflow 函数来涉及 GPU 吗?
谢谢
最佳答案
加快速度的唯一方法是不循环。在您的情况下,您可以尝试使用 rolling
使用您想要的时间跨度窗口,使用 Unix 时间戳作为日期时间索引(假设记录按时间戳排序,否则您需要先排序)。这对于 ip_seen
应该可以正常工作:
ip = myData['ip']
ip.index = pd.to_datetime(myData['unix'], unit='s')
myData['ip_seen'] = ip.rolling('5h')
.agg(lambda w: np.count_nonzero(w[:-1] == w[-1]))
.values.astype(np.int32)
但是,当聚合涉及多个列时,例如在 seen
列中,它会变得更加复杂。目前(参见 Pandas issue #15095)滚动函数不支持跨越两个维度的聚合。一种解决方法是将感兴趣的列合并到一个新的系列中,例如元组(如果值是数字可能会更好)或字符串(如果值已经是字符串可能会更好)。例如:
criteria = myData['ip'] + '|' + myData['device'] + '|' + myData['os']
criteria.index = pd.to_datetime(myData['unix'], unit='s')
myData['seen'] = criteria.rolling('5h')
.agg(lambda w: np.count_nonzero(w[:-1] == w[-1]))
.values.astype(np.int32)
编辑
显然 rolling
仅适用于数字类型,剩下两个选项:
翻转 myData
的索引(现在应该是 not 日期时间,因为 rolling
也不能使用它)和使用索引窗口获取必要的数据并进行操作:
# Use sequential integer index
idx_orig = myData.index
myData.reset_index(drop=True, inplace=True)
# Index to roll
idx = pd.Series(myData.index)
idx.index = pd.to_datetime(myData['unix'], unit='s')
# Roll aggregation function
def agg_seen(w, data, fields):
# Use slice for faster data frame slicing
slc = slice(int(w[0]), int(w[-2])) if len(w) > 1 else []
match = data.loc[slc, fields] == data.loc[int(w[-1]), fields]
return np.count_nonzero(np.all(match, axis=1))
# Do rolling
myData['ip_seen'] = idx.rolling('5h') \
.agg(lambda w: agg_seen(w, myData, ['ip'])) \
.values.astype(np.int32)
myData['ip'] = idx.rolling('5h') \
.agg(lambda w: agg_seen(w, myData, ['ip', 'device', 'os'])) \
.values.astype(np.int32)
# Put index back
myData.index = idx_orig
不过,这不是 rolling
的用途,我不确定这是否比循环提供更好的性能。
https://stackoverflow.com/questions/49172221/
相关文章:
spring-security - Spring Security OAuth2 资源服务器重试/弹
php - 如何使用 discord API 从用户名获取 discord 用户 ID
python - 如何使用pymongo在mongodb中创建索引
web-services - F# WsdlTypeProvider MaxReceivedMess
apache - Microsoft Edge localhost apache NTLM 始终尝试
iis - 如何在IIS服务器上阻止通过服务器IP地址访问网站?
csv - 如何从已上传到我们的 Google 云端硬盘的 CSV 自动导入和替换 Google 表
python - 如何在 Linux 上的 Python 中检查文件锁?