Программа Pandas и Numpy работает медленнее, чем петлевая версия с той же функциональностью, как ускорить работу? - PullRequest
0 голосов
/ 12 октября 2018

У меня есть миллионы записей, каждая из которых имеет целое число (p) и матрицу значений X * 3.Для каждой записи цель состоит в том, чтобы найти строку из матрицы по критериям выбора (см. Операторы if в коде).

Я довольно новичок в Python и пытаюсь использовать векторизацию в Pandasиспользуя параллельные вычисления вместо циклов.Я написал программу в двух версиях, одна с Pandas + Numpy, а другая с простыми циклами.

Мне сказали, что использование векторизации и операций с массивами Numpy быстрее, чем циклы.Но пока, версия цикла примерно в 10 раз быстрее: image

Вот программа:

import numpy as np
import pandas as pd
import time

d = {
    'values': [np.array([[1400,1400,1800000],[1500,1505,4800000],[1300,1305,5000]]), np.array([[800,900,80000],[1400,1420,50000],[1250,1300,60000]]), np.array([[1700,1750,5000000],[1900,1950,5000000],[1600,1600,3000000]]), np.array([])],
    'p': [1300, 1350, 1800, 1400]
}

# The Pandas+Numpy version

def selection_numpy(row):
    try:
        # Select rows where col[0] >= p
        c1 = row['values'][row['values'][:,0] >= row['p']]  

        # Select rows where col[2] > 1000000     
        c2 = c1[c1[:,2]>1000000]

        # Sort by col[0] and return the lowest row
        return c2[c2[:,0].argsort()][0]
    except:
        pass


start = time.time()

df = pd.DataFrame(d)
df['result'] = df.apply(selection_numpy, axis=1)
# print(df.head())
print(time.time()-start)

# The loop version:

def selection_loop(values, p):
    lowest_num = 9999999999
    lowest_item = None

    # Iterate through each row in the matrix and replace lowest_item if it's lower than the previous one
    for item in values:
        if item[0] >= p and item[2] > 1000000 and item[0] < lowest_num:
            lowest_num = item[0]
            lowest_item = item

    return lowest_item

start = time.time()

d['result'] = []
for i in range(0, 4):
    result = selection_loop(d['values'][i], d['p'][i])
    d['result'].append(result)
# print(d['result'])
print(time.time()-start)

Обе дают одинаковые значения результата, но версия цикла на несколько быстрее (для фактического набора данных миллионов записей, а не для 4 примеров записей.

Я предполагаю, что существует простое и элегантное решение для поиска нужной строки для каждой записи, которая использует векторизацию и является самой быстрой.Не уверен, почему функция, использующая массивы Numpy, такая медленная, но я ценю любые рекомендации.

...