2013-10-24 2 views
0

Итак, вот моя проблема. У меня есть список, состоящий из N подписок, состоящих из M элементов (поплавков) каждого. Таким образом, в общем виде это выглядит следующим образом:Получить информацию из подписок в главном списке элегантно

a_list = [b_list_1, b_list_2, ..., b_list_N] 

с:

b_list_i = [c_float_1, c_float_2, ..., c_float_M] 

Для этого примера предположим, N=9 ; M=3, так что список выглядит следующим образом:

a = [[1.1, 0.5, 0.7], [0.3, 1.4, 0.2], [0.6, 0.2, 1.], [1.1, 0.5, 0.3], [0.2, 1.1, 0.8], [1.1, 0.5, 1.], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9], [0.6, 0.2, 0.5]] 

мне нужно цикл через этот список, идентифицирующий те элементы, которые используют одни и те же первые два поплавка как тот же элемент, где третий поплавок должен быть усреднен перед хранением ING. Это означает, что я должен проверить, был ли элемент уже идентифицирован как повторяющийся ранее, поэтому я не идентифицирую его снова как новый элемент.

Чтобы дать более четкое представление о том, что я имею в виду, это то, что выход из списка a обработки должен выглядеть следующим образом:

a_processed = [[1.1, 0.5, 0.67], [0.3, 1.4, 0.2], [0.6, 0.2, 0.75], [0.2, 1.1, 0.8], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9]] 

Обратите внимание, что первый элемент в новом списке был идентифицирован три раза в (a[0], a[3] и a[5]), и поэтому он хранился с его третьим поплавом, усредненным ((0.7+0.3+1.)/3. = 0.67). Второй элемент не был повторен в a, поэтому он был сохранен как есть. Третий элемент был найден дважды в a (a[2] и a[8]) и хранился с его третьим поплавом, усредненным ((1.+0.5)/2.=0.75). Остальные элементы в новом списке не были найдены как повторяющиеся в a, поэтому они также были сохранены без изменений.

Поскольку я знаю, что обновление/изменение списка при прохождении через него не рекомендуется, я решил использовать несколько временных списков. Это код, который я придумал:

import numpy as np 

a = [[1.1, 0.5, 0.7], [0.3, 1.4, 0.2], [0.6, 0.2, 1.], [1.1, 0.5, 0.3], 
    [0.2, 1.1, 0.8], [1.1, 0.5, 1.], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9], 
[0.6, 0.2, 0.5]] 

# Final list. 
a_processed = [] 

# Holds indexes of elements to skip. 
skip_elem = [] 

# Loop through all items in a. 
for indx, elem in enumerate(a): 
    temp_average = [] 
    temp_average.append(elem)   
    # Only process if not found previously. 
    if indx not in skip_elem: 
     for indx2, elem2 in enumerate(a[(indx+1):]): 
      if elem[0] == elem2[0] and elem[1] == elem2[1]: 
       temp_average.append(elem2) 
       skip_elem.append(indx2+indx+1) 

     # Store 1st and 2nd floats and averaged 3rd float. 
     a_processed.append([temp_average[0][0], temp_average[0][1], 
          round(np.mean([i[2] for i in temp_average]),2)]) 

Этот код работает, но мне интересно, если там может быть более изящным/вещий способ сделать это. Он просто выглядит слишком запутанным (как я сказал, Fortran-esque).

+0

Это может быть лучше в кодере.stackexchange.com. – rlms

+0

Вам нужен конкретный заказ в 'a_processed'? Или любой порядок элементов будет делать? – goncalopp

+0

Любой заказ будет выполнен, я могу изменить их позже. – Gabriel

ответ

4

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

from collections import defaultdict 
nums = defaultdict(list) 
for arr in a: 
    key = tuple(arr[:2]) # make the first two floats the key 
    nums[key].append(arr[2]) # append the third float for the given key 

a_processed = [[k[0], k[1], sum(vals)/len(vals)] for k, vals in nums.items()] 

Используя это, я получить тот же результат, что и вы (хотя и в другом порядке):

[[0.2, 1.1, 0.8], [1.2, 0.3, 0.6], [0.3, 1.4, 0.2], [0.6, 0.4, 0.9], [1.1, 0.5, 0.6666666666666666], [0.6, 0.2, 0.75]] 

Если порядок a_processed является проблемой, вы можете использовать OrderedDict, как отметил @DSM.

+2

Другим способом сохранения порядка будет использование 'OrderedDict' вместо' defaultdict' и использование 'nums.setdefault (key, []). Append (arr [2])'. Затем, итерации над 'nums.items()' будут давать пары ключей, значений в порядке первого появления. – DSM

+0

Отличный ответ, спасибо! – Gabriel

4

Для сравнения: подход pandas. Если это действительно проблема обработки данных за кулисами, вы можете сэкономить много времени таким образом.

>>> a 
[[1.1, 0.5, 0.7], [0.3, 1.4, 0.2], [0.6, 0.2, 1.0], [1.1, 0.5, 0.3], [0.2, 1.1, 0.8], [1.1, 0.5, 1.0], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9], [0.6, 0.2, 0.5]] 
>>> df = pd.DataFrame(a) 
>>> df.groupby([0,1]).mean() 
       2 
0 1    
0.2 1.1 0.800000 
0.3 1.4 0.200000 
0.6 0.2 0.750000 
    0.4 0.900000 
1.1 0.5 0.666667 
1.2 0.3 0.600000 

Эта проблема достаточно распространена, что это однострочный. Вы можете использовать именованные столбцы, вычислить множество других полезных статистических данных, обрабатывать отсутствующие данные и т. Д.

+0

Это выглядит удивительно просто, но, к сожалению, я не могу использовать 'pandas' в настоящее время (не установлен в кластере, который я использую), я обязательно проверю этот пакет. Спасибо! – Gabriel

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