Попробуйте это:
B = [(a[0], average(filter(lambda elt: elt != x, a[1:]))) for a in A]
Производительность может быть улучшена при использовании ifilter
из itertools
, особенно для больших матриц. Это должно дать ожидаемый результат без изменения функции average
или изменения A
.
EDIT
Вы можете рассмотреть возможность реализации вашей матрицы по-другому, если она редка. Если вы хотите сохранить текущую реализацию, вы должны использовать значение None
для представления пропущенных значений. Это эквивалент Python для null
, с которым вы, возможно, знакомы по другим языкам.
То, как вы реализуете матрицу, кардинально меняет способ реализации нужных вам функций, и я попытаюсь осветить ваш путь и альтернативный метод, который мог бы быть более эффективным для разреженных матриц.
Для обоих я буду использовать ваш пример матрицы с отверстиями:
# matrix A with row headings and values
A = [('Apple',0.95, x, 0.89, 0.87, 0.93),
('Bear', 0.33, 0.25, 0.85, 0.44, 0.33),
('Crab', x, 0.55, 0.10, x, 0.22)]
Список списков (или кортежей, или чего-либо еще)
Как я уже говорил, используйте None
для пустого значения:
A = [('Apple', 0.95, None, 0.89, 0.87, 0.93),
('Bear', 0.33, 0.25, 0.85, 0.44, 0.33),
('Crab', None, 0.55, 0.10, None, 0.22)]
B
похоже на то, что я написал ранее:
B = [(a[0], average(filter(lambda x: x is not None, a[1:]))) for a in A]
Определите column
как генератор (повторяемый), который возвращает только заполненные значения:
def column(M, i):
i += 1 # this will allow you to use zero-based indices if you want
return (row[i] for row in M if row[i] is not None)
Тогда вы сможете реализовать minus
проще и эффективнее:
from operator import sub
from itertools import imap, repeat
def minus(M, i):
return list(imap(sub, repeat(1.0), column(M, i)))
Словари
Другой способ представить вашу матрицу - это Python dict
s. Здесь есть некоторые преимущества, особенно в том, что вы не тратите место для хранения, если в матрице много дырок. Недостатком этого метода является то, что создание матрицы может быть более сложной задачей в зависимости от того, как вы ее построили.
Ваш пример может стать (пробел для ясности):
A = [('Apple', dict([(0, 0.95), (2, 0.89), (3, 0.87), (4, 0.93)])),
('Bear', dict([(0, 0.33), (1, 0.25), (2, 0.85), (3, 0.44), (4, 0.33)])),
('Crab', dict([ (1, 0.55), (2, 0.10), (4, 0.22)]))]
Это некрасивый способ создать его наверняка, но если вы строите матрицу из других данных с помощью цикла, это может быть намного приятнее.
Сейчас
B = [(a[0], sum(a[1].itervalues())/len(a[1])) for a in A2]
Это ужаснее, чем должно быть, но я не очень хорош в Python и не могу заставить его делать именно то, что я хочу ...
Вы можете определить column
функцию, которая возвращает генератор, который будет более эффективным, чем понимание списка:
def column(M, i):
return (row[1][i] for row in M if i in row[1])
minus
выполняется точно так же, как в другом примере.
У меня такое чувство, что я чего-то не понимаю в том, что вы хотите, поэтому не стесняйтесь, дайте мне знать, что нужно исправить. Кроме того, мое отсутствие кода Python, вероятно, не оправдывало версию словаря, но это может быть эффективно для разреженных матриц. Весь этот пример будет проще, если вы создадите матричный класс, тогда вы сможете переключать реализации и смотреть, что лучше для вас. Удачи.