Эффективное добавление списка списков в pandas DataFrame - PullRequest
1 голос
/ 17 апреля 2020

У меня есть программа с вложенной структурой, которая в настоящее время написана с использованием очевидного подхода для добавления списка списков к верхнему уровню DataFrame (путем создания DataFrame из этого списка списков и затем добавив это к цели DataFrame):

import pandas as pd

columns=["inner", "outer", "col1", "col2", "col3", "col4"]
def create_children(inner, outer):
    results = []
    for i in range(inner):
        results.append([f'{i}', f'{outer}', 'a', 'b', 'c', 'd'])

    return results

def test(outer, inner):
    df = pd.DataFrame(columns=columns)
    for i in range(outer):
        children = create_children(inner, i)
        child_df = pd.DataFrame(children, columns=columns)
        df = pd.concat([df, child_df]) # Faster than append

    return df

Проблема в том, что когда я профилирую это, создание дочернего элемента DataFrame занимает серьезное количество времени:

Timer unit: 1e-06 s

Total time: 0.012352 s
File: <ipython-input-43-d816d566eb1b>
Function: test at line 1

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     1                                           def test(outer, inner):
     2         1       5542.0   5542.0     44.9      df = pd.DataFrame(columns=columns)
     3         3          5.0      1.7      0.0      for i in range(outer):
     4         2         10.0      5.0      0.1          children = create_children(inner, i)
     5         2       4341.0   2170.5     35.1          child_df = pd.DataFrame(children, columns=columns)
     6         2       2454.0   1227.0     19.9          df = pd.concat([df, child_df])
     7                                           # Works in this case but problems with an index and slightly slower
     8                                           #         df = df.append(child_df)
     9                                           
    10         1          0.0      0.0      0.0      return df

Если я переписываю этот простой пример для создания только DataFrame в конце, то он значительно быстрее:

def test2(outer, inner):
    all_children = []
    for i in range(outer):
        children = create_children(inner, i)
        all_children.extend(children)

    df = pd.DataFrame(all_children, columns=columns)

    return df

Предоставление:

Timer unit: 1e-06 s

Total time: 0.002104 s
File: <ipython-input-44-05d8d95dfe60>
Function: test2 at line 1

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     1                                           def test2(outer, inner):
     2         1          1.0      1.0      0.0      all_children = []
     3         3          4.0      1.3      0.2      for i in range(outer):
     4         2          8.0      4.0      0.4          children = create_children(inner, i)
     5         2          2.0      1.0      0.1          all_children.extend(children)
     6                                           
     7         1       2088.0   2088.0     99.2      df = pd.DataFrame(all_children, columns=columns)
     8                                                   
     9         1          1.0      1.0      0.0      return df

К сожалению, рассматриваемая программа использует DataFrame функции во внешнем l oop, поэтому я не могу просто исключить использование DataFrame. (Моя конечная цель - сделать это, но это довольно трудоемкий рефакторинг.)

Мой вопрос таков: есть ли способ добавить соответствующий список списков в DataFrame без создания промежуточный DataFrame, что, по-видимому, влечет за собой большие накладные расходы?

1 Ответ

1 голос
/ 19 апреля 2020

Я бы предложил сохранить промежуточные данные в словаре и добавить этот словарь в список. В конце вы можете просто создать свой окончательный DataFrame:

columns=["inner", "outer", "col1", "col2", "col3", "col4"]
def create_children(inner, outer):
results = []
for i in range(inner):
    dct = {'inner': some_value,
           ....,
          {'col4':  another_value,
    results.append(dct)
return results

def test(outer, inner):
all_results = []
for i in range(outer):
    children = create_children(inner, i)
    all_results.extend(children)

df = pd.DataFrame(all_results, columns=columns)
return df
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...