2015-01-16 5 views
0

Существует множество рецептов для выравнивания вложенного списка. Я скопировать решение здесь только для справки:Сглаживание и развязка вложенного списка массивов numpy

def flatten(x): 
    result = [] 
    for el in x: 
     if hasattr(el, "__iter__") and not isinstance(el, basestring): 
     result.extend(flatten(el)) 
     else: 
     result.append(el) 
    return result 

То, что я заинтересован в это обратная операция, которая перестраивает список в оригинальном формате. Например:

L = [[array([[ 24, -134],[ -67, -207]])], 
    [array([[ 204, -45],[ 99, -118]])], 
    [array([[ 43, -154],[-122, 168]]), array([[ 33, -110],[ 147, -26],[ -49, -122]])]] 

# flattened version 

L_flat = [24, -134, -67, -207, 204, -45, 99, -118, 43, -154, -122, 168, 33, -110, 147, -26, -49, -122] 

Есть ли эффективный способ сглаживания, сохранения индексов и восстановления до его первоначального формата?

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

Конечно, функция сглаживания также должна быть изменена для сохранения структуры списка и формы массивов numpy.

+1

Как вы должны знать, из сплющенной версии, изначально это было? Вы потеряли информацию в процессе сглаживания. – jonrsharpe

+0

Конечно, функция сглаживания должна быть изменена для сохранения структуры списка. – memecs

+0

В какой-то степени вы ответили на свой вопрос; вам нужно изменить 'flatten', чтобы сохранить информацию о структуре списка и формах массивов внутри него. Например, он мог бы возвращать '[[(2, 2)], [(2, 2)], [(2, 2), (3, 2)]]' рядом с сплющенным 'L'. Затем вам придется нарезать 'L_flat' соответственно и« переформатировать »массивы из каждого фрагмента. – jonrsharpe

ответ

1

Вы строите парадокс: вы хотите сгладить объект, но вы не хотите сгладить объект, сохраняя его структурную информацию где-нибудь в объекте.

Так вещий способ сделать это не выравниваться объект, но написать класс, который будет иметь __iter__, что позволяет последовательно (то есть. Расправленными) пройти через элементы базового объекта , Это будет примерно так же быстро, как преобразование в плоскую вещь (если применяется только один раз для элемента), и вы не дублируете или не изменяете оригинальный не-плоский контейнер.

0

Вот что я придумал, что оказалось на 30 раз быстрее, чем повторение по вложенному списку и загрузка по отдельности.

def flatten(nl): 
    l1 = [len(s) for s in itertools.chain.from_iterable(nl)] 
    l2 = [len(s) for s in nl] 

    nl = list(itertools.chain.from_iterable(
     itertools.chain.from_iterable(nl))) 

    return nl,l1,l2 

def reconstruct(nl,l1,l2): 
    return np.split(np.split(nl,np.cumsum(l1)),np.cumsum(l2))[:-1] 

L_flat,l1,l2 = flatten(L) 
L_reconstructed = reconstruct(L_flat,l1,l2) 

Лучшее решение будет работать итеративно для произвольного количества вложенных уровней.

+0

Почему проголосовали? – memecs

2

Я искал решение, чтобы сплющить и unflatten вложенных списков Numpy массивов, но только нашел этот вопрос без ответа, так что я пришел с этим:

def _flatten(values): 
    if isinstance(values, np.ndarray): 
     yield values.flatten() 
    else: 
     for value in values: 
      yield from _flatten(value) 

def flatten(values): 
    # flatten nested lists of np.ndarray to np.ndarray 
    return np.concatenate(list(_flatten(values))) 

def _unflatten(flat_values, prototype, offset): 
    if isinstance(prototype, np.ndarray): 
     shape = prototype.shape 
     new_offset = offset + np.product(shape) 
     value = flat_values[offset:new_offset].reshape(shape) 
     return value, new_offset 
    else: 
     result = [] 
     for value in prototype: 
      value, offset = _unflatten(flat_values, value, offset) 
      result.append(value) 
     return result, offset 

def unflatten(flat_values, prototype): 
    # unflatten np.ndarray to nested lists with structure of prototype 
    result, offset = _unflatten(flat_values, prototype, 0) 
    assert(offset == len(flat_values)) 
    return result 

Пример:

a = [ 
    np.random.rand(1), 
    [ 
     np.random.rand(2, 1), 
     np.random.rand(1, 2, 1), 
    ], 
    [[]], 
] 

b = flatten(a) 

# 'c' will have values of 'b' and structure of 'a' 
c = unflatten(b, a) 

Выход:

a: 
[array([ 0.26453544]), [array([[ 0.88273824], 
     [ 0.63458643]]), array([[[ 0.84252894], 
     [ 0.91414218]]])], [[]]] 
b: 
[ 0.26453544 0.88273824 0.63458643 0.84252894 0.91414218] 
c: 
[array([ 0.26453544]), [array([[ 0.88273824], 
     [ 0.63458643]]), array([[[ 0.84252894], 
     [ 0.91414218]]])], [[]]] 

лицензия: WTFPL

Смежные вопросы