python - 如何加速遍历数组/矩阵?尝试了 pandas 和 numpy 数组

我想通过大型二维数组 (15,100m) 进行一些特征丰富。

处理包含 100,000 条记录的示例集表明我需要更快地完成此操作。

编辑(数据模型信息)

为简化起见,假设我们只有两个相关列:

  • IP(标识符)
  • Unix(自 1970 年以来以秒为单位的时间戳)

我想添加第 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仅适用于数字类型,剩下两个选项:

  1. 处理数据以使用数字类型。对于 IP,这很容易,因为它实际上代表一个 32 位数字(如果我猜是 IPv6,则为 64)。对于设备和操作系统,假设它们现在是字符串,它会变得更加复杂,您必须将每个可能的值映射到一个整数并将其与长值中的 IP 合并,例如将它们放在更高位或类似的位置(对于 IPv6 甚至可能是不可能的,因为 NumPy 目前支持的最大整数是 64 位)。
  2. 翻转 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 中检查文件锁?

javascript - 如何让 chrome.webRequest 等待 XMLHttpReque

javascript - i18next-json-sync 使用问题