#python #pandas #pandas-groupby
#python #pandas #pandas-groupby
Вопрос:
Я пытаюсь создать тензор из фрейма данных, который содержит области последовательных данных.
Попытки, которые я придумал, используют groupby / aggregate, аналогичные df.groupby(groupcol)[aggcol].agg(list)
типу команды, которая легко получает список столбца (aggcol) на основе группировки отдельного столбца (groupcol)
Вот пример двух входных фреймов данных (объектов и их метаданных) и результирующего фрейма данных (аннотированных объектов по метаданным и позиции), который должен быть обработан:
Я работаю над группировкой этих функций в список для каждого региона:
Но это должно быть дополнено до определенной длины для каждого региона (например, путем добавления строк на каждый уровень региона во фрейме данных аннотированных объектов).
Другими словами, результирующий фрейм данных после группировки по регионам будет:
Таким образом, я могу вернуть массив значений в этом фрейме данных в этом формате:
array([[[2.965e 03, 4.800e-01],
[4.894e 03, 8.700e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[7.920e 02, 1.700e-01],
[3.029e 03, 8.100e-01],
[4.852e 03, 7.400e-01],
[9.548e 03, 6.000e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[2.469e 03, 3.600e-01],
[7.144e 03, 1.600e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[5.783e 03, 7.000e-01],
[7.068e 03, 6.000e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[2.965e 03, 9.800e-01],
[4.894e 03, 8.900e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[7.920e 02, 8.600e-01],
[3.029e 03, 8.600e-01],
[4.852e 03, 6.900e-01],
[9.548e 03, 5.900e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[2.469e 03, 6.700e-01],
[7.144e 03, 1.300e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[5.783e 03, 8.400e-01],
[7.068e 03, 9.900e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[2.965e 03, 8.000e-02],
[4.894e 03, 5.700e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[7.920e 02, 4.000e-01],
[3.029e 03, 1.100e-01],
[4.852e 03, 8.000e-01],
[9.548e 03, 3.400e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[2.469e 03, 1.800e-01],
[7.144e 03, 6.300e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]],
[[5.783e 03, 4.700e-01],
[7.068e 03, 3.200e-01],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00],
[0.000e 00, 0.000e 00]]])
Вот код для создания входных таблиц:
import numpy as np
import pandas as pd
# DataFrame of Features in each document
num_features = 10
num_docs = 3
def calc_feats():
return np.random.randint(0, 100, num_features)/100
d = {'document_' str(i): calc_feats() for i in range(0, num_docs)}
# Unique feature index
d['feat_index'] = np.arange(0, num_features)
docs = pd.DataFrame(d)
.set_index('feat_index')
# DataFrame for metadata about features
regions_of_doc = ['mid', 'end', 'start', 'intro', 'title']
feature_regions = [np.random.choice(regions_of_doc) for i in range(0, num_features)]
feature_positions = np.random.randint(0, 10000, num_features)
feature_meta_info = pd.DataFrame({'feat_index': d['feat_index'],
'region': feature_regions,
'position_in_region': feature_positions,
'other_uninteresting_info': np.random.randint(0, 10000, num_times)})
.set_index('feat_index')
# Join the two dataframes and set a multi-index to annotate the documents
combined_df = docs.join(feature_meta_info.drop('other_uninteresting_info', axis = 1))
.reset_index()
.set_index(['region', 'feat_index', 'position_in_region'])
.sort_index(level = ['region', 'position_in_region'])
# add position features to each feature
pos = combined_df.index.get_level_values('position_in_region')
combined_df = combined_df.apply(lambda x: list(zip(pos, x)))
# display(multi_table([docs, feature_meta_info, ]))
display(HTML('<table><tr style="background-color:white;">'
'<td>' docs._repr_html_() '</td>'
'<td><img src = "https://upload.wikimedia.org/wikipedia/commons/9/9e/Plus_symbol.svg", width = "50", height = "50"></td>'
'<td>' feature_meta_info._repr_html_() '</td>'
'<td><img src = "https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Arrow_east.svg/800px-Arrow_east.svg.png", width = "50", height = "10"></td>'
'<td>' combined_df._repr_html_() '</td>'
'</tr></table>'))
Комментарии:
1. Не могли бы вы добавить ожидаемый результат в виде фрейма данных, чтобы мы могли визуально видеть, что вы пытаетесь сделать
2. @ Efran — Это то, что я изобразил на картинке. Однако, конечно, если бы я был способен создать его полностью , мне не нужно было бы задавать этот вопрос. Поскольку я не смог получить именно то, что хотел, я поместил что-то очень близкое к изображению. Единственное различие, которое мне нужно, это то, что каждое значение нормализуется до определенной длины и сортируется по одной оси (оси положения), а ось положения нормализуется между 0 и 1.
3. @Erfan Код должен быть полным, чтобы сгенерировать то, что я ищу, — если он не выдал ошибку.
4. Я думаю, что он имеет в виду, можете ли вы вручную (т. Е. Ввести каждую строку выходной таблицы в своем сообщении) создать, как должна выглядеть выходная таблица. Его трудно понять.
Ответ №1:
После написания нескольких минимальных, полных и проверяемых примеров и аналогий по этому вопросу у меня есть некоторый работающий код. Это может быть неэффективно (собираюсь проверить это), но это способ сделать это с помощью множества stack()
sort_index()
groupby()
функций и:
# stack documents into series
# and then and order the index by document first, then region and position
featvals = combined_df.stack()
featvals.index.set_names(['region','feat_index','position_in_region', 'document'], inplace = True)
featvals = featvals.reorder_levels(order = ['document', 'region', 'position_in_region', 'feat_index'])
.sort_index(level = ['document', 'region', 'position_in_region'])
display(featvals.to_frame())
# Group into lists by each document and region for each feature tuple
feat_by_region = featvals.groupby(level = ['document', 'region']).agg(list)
display(feat_by_region.to_frame())
def pad_lists(list_of_arrays, max_seq_len, null_value):
arr = np.array([list(i) [null_value] * (max_seq_len - len(i)) for i in list_of_arrays])
return arr
# Solution:
# Numpy array by getting the lists by `.values` and pad these arrays to a standardized length
feat_by_region_array = pad_lists(feat_by_region.values, max_seq_len = 7, null_value = (0,0))
# dataframe to view the feature array
feat_by_region = pd.DataFrame([tuple(i) for i in feat_by_region_array[..., :]], index = feat_by_region.index)
feat_by_region.columns.name = 'position_index'
display(feat_by_region)
# doesn't condense to properly formatted array (- because of tuples?)
display(np.array(feat_by_region.values).shape)
вывод:
укладка / упорядочение:
группировка в списки:
фрейм данных значений после заполнения: