Оптимизирующий комплекс Pandas операция - PullRequest
0 голосов
/ 15 января 2020

У меня есть Pandas DataFrame, содержащий положительные целые числа и словарь метаданных. Ключи словаря соответствуют столбцам DataFrame, а значения словаря на 1 больше максимально возможного значения в столбце. Вот пример возможного словаря DataFrame и метаданных:

import numpy as np 
import pandas as pd

def create_random_df(schema, nrows=10):
    df = pd.DataFrame()
    for k, v in schema.items():
        df[k] = np.random.randint(0, v, nrows)
    return df

schema_dict = {0: 3, 
               1: 2,
               2: 4
              }

df = create_random_df(schema_dict)
print(df)

    0   1   2
0   1   1   1
1   1   1   3
2   0   1   1
3   0   0   0
4   1   1   0
5   1   1   0
6   1   0   2
7   0   1   1
8   0   0   3
9   0   1   2

Обратите внимание, что в столбце 0 словарь указывает, что возможными значениями столбца являются 0, 1, 2, но есть только 0 и 1.

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

{'0_0': 0.5,
 '0_1': 0.5,
 '0_2': 0,
 '1_0': 0.3,
 '1_1': 0.7,
 '2_0': 0.3,
 '2_1': 0.3,
 '2_2': 0.2,
 '2_3': 0.2}

, поскольку в столбце 0 есть 50% 0 и 50% 1 с 0% 2. То, как я сейчас это делаю, заключается в создании вложенного словаря и его выравнивании:

import collections

def create_prop_dict(df, schema):
    prop_dict = {idx: {k:0 for k in range(possible_values)} for idx, possible_values in schema.items()}
    for i in range(len(prop_dict)):
        prop_dict[i].update(df[i].value_counts(normalize=True))
    return prop_dict

def flatten(d, parent_key='', sep='_'):
    items = []
    for k, v in d.items():
        new_key = str(parent_key) + sep + str(k) if parent_key else str(k)
        if isinstance(v, collections.MutableMapping):
            items.extend(flatten(v, new_key, sep=sep).items())
        else:
            items.append((new_key, v))
    return dict(items)

prop_dict = flatten(create_prop_dict(df, schema_dict))
print(prop_dict)

{'0_0': 0.5,
 '0_1': 0.5,
 '0_2': 0,
 '1_0': 0.3,
 '1_1': 0.7,
 '2_0': 0.3,
 '2_1': 0.3,
 '2_2': 0.2,
 '2_3': 0.2}

В этом примере это работает нормально, но когда DataFrame большой, он довольно медленный. Например, с большим DataFrame:

schema_dict_large = {k: np.random.randint(1, 50) for k in range(5000)}
df_large = create_random_df(schema_dict_large, 1000) # df_large.shape==(1000,5000)

%timeit prop_dict_large = flatten(create_prop_dict(df_large, schema_dict_large))
5.2 s ± 73.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Как создать словарь пропорций максимально эффективно? Я посмотрел на Cython и Numba, но они не работают с вложенными словарями.

1 Ответ

2 голосов
/ 15 января 2020

Другое решение:

out = {}
for c in df.columns:
    g = df.groupby(c)[c].count() / len(df[c])
    d = g.to_dict()
    for v in range(schema_dict[c]):
        out['{}_{}'.format(c, v)] = d.get(v, 0)

from pprint import pprint
pprint(out)

Печать (например):

{'0_0': 0.5,
 '0_1': 0.5,
 '0_2': 0,
 '1_0': 0.5,
 '1_1': 0.5,
 '2_0': 0.4,
 '2_1': 0.1,
 '2_2': 0.3,
 '2_3': 0.2}

РЕДАКТИРОВАТЬ: timeit результаты для большого DataFrame:

3.5940384549976443 # my solution
5.389242456003558  # original solution
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...