агрегация и группировка панд: группировка нескольких столбцов, сортировка, заполнение и сохранение массива - PullRequest
0 голосов
/ 14 апреля 2019

Я пытаюсь создать тензор из кадра данных, который содержит области последовательных данных.

Попытки, которые я придумал, используют groupby / aggregate, подобный команде типа df.groupby(groupcol)[aggcol].agg(list), которая легко получает список столбцов (aggcol) на основе группировки отдельного столбца (groupcol)

Вот пример двух входных фреймов данных (объекты и их метаданные) и результирующий фрейм данных (аннотированные объекты по метаданным и положению), которые должны быть обработаны:

enter image description here

Я работаю над объединением этих функций в список для каждого региона:

enter image description here

Но это должно быть дополнено определенной длиной для каждого региона (например, путем добавления строк к каждому уровню региона в кадре аннотированных объектов).

Другими словами, результирующий кадр данных после группировки по регионам будет:

enter image description here

Так, чтобы я мог вернуть массив значений в этом кадре данных в следующем формате:

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 Ответ

0 голосов
/ 15 апреля 2019

После написания нескольких минимальных, полных и проверяемых примеров и аналогий по этому поводу у меня есть код, который работает.Это может быть неэффективно (собирается проверить это), но это способ сделать это с тоннами функций 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)

output:

составление / упорядочение:

enter image description here

группировка по спискам:

enter image description here

кадр данных значений после заполнения:

enter image description here

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