У меня есть интересная проблема, которую я исправил на поверхностном уровне, но я хотел бы улучшить и улучшить мою реализацию.
У меня есть DataFrame, который содержит набор данных для последующего машинного обучения. Имеет столбцы объектов (около 500) и 4 столбца целей. Цели связаны друг с другом в возрастающей степени детализации (например, ошибка / отсутствие_файла, ошибка-где, группа ошибок, ошибка-точная).
DataFrame имеет довольно много значений NaN, так как он был скомпилирован из 2 отдельных наборов данных с помощью соединения OUTER - некоторые строки заполнены, другие содержат данные из одного набора данных, но не из другого и т. Д. - см. Рисунок ниже, и извините за ужасный редактирует.
В любом случае, Transformer от Sci-kit Learn SimpleImputer () не дал мне результатов ML, к которым я стремился, и я подумал, что, возможно, мне следует провести вменение на основе целей, как, например, в. вычислите среднее значение для выборок, доступных для каждой цели в каждом столбце, и рассчитайте их. Затем проверьте, если остались какие-либо значения NaN, и, если они есть, перейдите к tar_3 (на один уровень детализации вниз), вычислите также медиану и рассчитайте это значение для каждой цели, для каждого столбца. И так до тех пор, пока не останется ни одного NaN.
Я реализовал это с помощью приведенного ниже кода, который, как я полностью понимаю, неуклюж, как и требует выполнения навсегда:
tar_list = ['tar_4', 'tar_3', 'tar_2', 'tar_1']
for tar in tar_list:
medians = df.groupby(by = tar).agg('median')
print("\nFilling values based on {} column granularity.".format(tar))
for col in [col for col in df.columns if col not in tar_list]:
print(col)
uniques = sorted(df[tar].unique())
for class_name in uniques:
value_to_fill = medians.loc[class_name][col]
print("Setting NaNs for target {} in column {} to {}".format(class_name, col, value_to_fill))
df.loc[df[tar] == class_name, col] = df.loc[df[tar] == class_name, col].fillna(value = value_to_fill)
print()
Хотя я доволен результатом, который дает этот код, у него есть 2 недостатка, которые я не могу игнорировать:
1) Требуется вечность, чтобы выполнить даже на моем маленьком наборе данных ~ 1000 выборок x ~ 500 столбцов.
2) Он вменяет одно и то же медианное значение для всех NaN в каждом столбце для целевого значения, над которым он в настоящее время работает. Я бы предпочел, чтобы он вменял что-то с небольшим шумом, чтобы предотвратить просто повторение данных (может быть, либо значение, случайно выбранное из нормального распределения значений в этом столбце для этой цели?).
Насколько мне известно, в Sci-Kit Learn или Pandas нет готовых инструментов для более эффективного решения этой задачи. Однако, если есть - может кто-то направить меня в правильном направлении? Кроме того, я открыт для предложений о том, как улучшить этот код для решения обеих моих проблем.
UPDATE:
Пример генерирования кода, о котором я упоминал:
df = pd.DataFrame(np.random.randint(0, 100, size=(vsize, 10)),
columns = ["col_{}".format(x) for x in range(10)],
index = range(0, vsize * 3, 3))
df_2 = pd.DataFrame(np.random.randint(0,100,size=(vsize, 10)),
columns = ["col_{}".format(x) for x in range(10, 20, 1)],
index = range(0, vsize * 2, 2))
df = df.merge(df_2, left_index = True, right_index = True, how = 'outer')
df_tar = pd.DataFrame({"tar_1": [np.random.randint(0, 2) for x in range(vsize * 3)],
"tar_2": [np.random.randint(0, 4) for x in range(vsize * 3)],
"tar_3": [np.random.randint(0, 8) for x in range(vsize * 3)],
"tar_4": [np.random.randint(0, 16) for x in range(vsize * 3)]})
df = df.merge(df_tar, left_index = True, right_index = True, how = 'inner')