Панды pd.Series () и pd.DataFrame () очень медленные - PullRequest
0 голосов
/ 17 октября 2019

Мне нужна помощь, чтобы улучшить производительность следующего кода.

        for object in dict_of_objects.values():
            test = pd.Series(object.properties)    #properties is a dict
            series_list.append(test)

        # List comprehension is not really faster than the loop since pd.Series() takes most time
        #series_list = [pd.Series(object.properties) for object in dict_of_objects.values()]

        # Also very slow
        df = pd.DataFrame(series_list)

После некоторой синхронизации кода я обнаружил, что pd.Series(object.properties) и pd.DataFrame(series_list) очень медленные - оба требуют около 9 секунддля завершения пока добавить нужно всего 0,4 с. В результате понимание списка на самом деле не является улучшением, поскольку оно также вызывает pd.Series (object.properties).

Есть ли у вас какие-либо предложения о том, как улучшить производительность этого?

Бест, Юлз

Ответы [ 2 ]

2 голосов
/ 17 октября 2019

Давайте посмотрим на некоторые фрагменты кода:

import numpy as np
import pandas as pd
from copy import deepcopy as cp

N_objects = 10
N_samples = 10000

class SimpleClass:
    def __init__(self,prop):
        self.properties = prop

dict_of_objects = {'obj{}'.format(i): 
                        SimpleClass({
                                        'alice' : np.random.rand(N_samples),
                                        'bob'   : np.random.rand(N_samples)
                                    }) for i in range(N_objects)}

def slow_update(dict_of_objects):
    series_list = []
    for obj in dict_of_objects.values():
        test = pd.Series(obj.properties)
        series_list.append(test)
    return pd.DataFrame(series_list)

def med_update(dict_of_objects):
    return pd.DataFrame([pd.Series(obj.properties) for obj in dict_of_objects.values()])

def fast_update(dict_of_objects):
    keys = iter(dict_of_objects.values()).__next__().properties.keys()
    return pd.DataFrame({k: [obj.properties[k] for obj in dict_of_objects.values()] for k in keys})

И с таймингами:

>>> %timeit slow_update(dict_of_objects)
2.88 ms ± 19.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit med_update(dict_of_objects)
2.86 ms ± 23.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit fast_update(dict_of_objects)
344 µs ± 17.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Быстрое обновление делает следующее:

  1. Захватитеполя из итератора с одним использованием __next__.
  2. Построение полей с использованием списка.
  3. Построение структуры данных с использованием словарного понимания.

Это оВ 8 раз быстрее, чем большинство методов.

Редактировать: , как правильно указал @koPytok, fast_update не будет работать, если атрибут properties каждого объекта имеет разные ключи . Это стоит иметь в виду, если вы решите реализовать это для чего-то такого, как захват базы данных NoSQL - в MongoDB документы не должны иметь одни и те же поля (здесь поменяйте местами документ для объекта, поле для ключа).

Наслаждайтесь!

2 голосов
/ 17 октября 2019

Такой же результат может быть достигнут, например, как показано ниже:

properties_list = [o.properties for o in dict_of_objects.values()]
df = pd.DataFrame(properties_list).T

или с dict() свойствами, для которых требуется меньше операций:

properties_dict = {k: o.properties for k, o in dict_of_objects.items()}
df = pd.DataFrame.from_dict(properties_dict)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...