Преобразовать списки кортежей в массив, где первым элементом в каждом кортеже является индекс массива? - PullRequest
0 голосов
/ 15 марта 2019

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

Итак, у меня есть:

a = [(0, 2.45), (1, 3.25), (2, 5.34)]
b = [(0, 7.46), (1, 5.64), (3, 3.45)]
c = [(0, 9.65), (1, 7.22)]

И я хочу:

somefun(a, b, c)
>>> array([(2.45, 3.25, 5.34, 0.  ), (7.46, 5.64, 0.  , 3.45), (9.65, 7.22, 0.  , 0.  ])

У меня сейчас есть решение, которое перебирает списки, создает структурированные массивы с назначенными столбцами, а затем использует numpy.lib.refunction.stack_array(), но этот подход довольно медленный:

from numpy.lib import refunctions as rfn

row_list = []
for row in [a, b]:
    index = [(str(i[0]), 'f4') for i in row]
    value = [tuple([i[1] for i in row])]
    row_list.append(np.array(value, dtype=index))

result = np.ma.filled(rfn.stack_arrays(row_list, usemask=True), fill_value = 0)

У меня есть десяткииз тысяч таких списков, которые я хочу объединить в массив, поэтому я ищу что-то быстрее.Может быть, есть более подходящий numpy метод, о котором я не знаю.Спасибо за помощь.

1 Ответ

2 голосов
/ 16 марта 2019

Вы можете использовать следующую функцию:

from itertools import chain

a = [(0, 2.45), (1, 3.25), (2, 5.34)]
b = [(0, 7.46), (1, 5.64), (3, 3.45)]
c = [(0, 9.65), (1, 7.22)]

def func(*lists):
    max_ind = max(ind for ind, _ in chain.from_iterable(lists))
    result = []
    for l in lists:
        d = dict(l)
        t = tuple(d.get(ind, 0.) for ind in range(max_ind + 1))
        result.append(t)
    return result

print(func(a, b, c))
# [(2.45, 3.25, 5.34, 0.0), (7.46, 5.64, 0.0, 3.45), (9.65, 7.22, 0.0, 0.0)]

В качестве альтернативы вы можете использовать itemgetter() с defaultdict():

from itertools import chain
from collections import defaultdict
from operator import itemgetter

def func(*lists):
    max_ind = max(ind for ind, _ in chain.from_iterable(lists))
    iget = itemgetter(*range(max_ind + 1))
    return [iget(defaultdict(float, l)) for l in lists]

print(func(a, b, c))
# [(2.45, 3.25, 5.34, 0.0), (7.46, 5.64, 0.0, 3.45), (9.65, 7.22, 0.0, 0.0)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...