У меня есть 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, но они не работают с вложенными словарями.