понимание дыр в матрице - PullRequest
       11

понимание дыр в матрице

0 голосов
/ 06 октября 2011

Это ответвление предыдущего вопроса, который начал снежный ком. Если у меня есть матрица A и я хочу использовать среднее / среднее значение каждой строки [1:], чтобы создать другую матрицу B, но сохранить заголовки строк без изменений, это понимание списка работает.

from operator import mul,len

# matrix A with row headings and values
A = [('Apple',0.95,0.99,0.89,0.87,0.93),
('Bear',0.33,0.25.0.85,0.44,0.33),
('Crab',0.55,0.55,0.10,0.43,0.22)]

#List Comprehension
def average(lst):
    return sum(lst) / len(lst)

B = [(a[0], average(a[1:])) for a in A]

Ожидаемый результат

B = [('Apple', 0.926), ('Bear', 0.44), ('Crab', 0.37)]

Однако, если в наборе данных есть дыры (обозначенные «x»), анализ не будет запущен, т.е.

# 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)]

В матрице, где относительное расположение каждой строки и столбца что-то значит, я не могу просто удалить «пустые» записи, так как я могу заполнить или пропустить их и заставить это работать снова? Оглядываясь назад, мои данные имеют больше дыр, чем старая простыня.

Кроме того, как бы я предложил фильтры, предложенные ниже, в следующих определениях (которые заглушаются, когда они попадают в нечто, не являющееся числом), чтобы при нажатии значения 'X' возвращалось другое значение 'X'?

    def plus(matrix, i):
        return [row[i] for row in matrix]

    def minus(matrix, i):
        return [1.00-row[i] for row in matrix]

Ответы [ 3 ]

0 голосов
/ 06 октября 2011

В average() используйте цикл, чтобы удалить все значения x из списка с помощью lst.remove(x), прежде чем вычислять среднее значение (вам придется отлавливать ошибку, генерируемую remove(), когда не удается найти то, чтоон ищет).

Я рекомендую использовать что-то вроде "" для обозначения отверстий, если у вас уже что-то есть.

0 голосов
/ 06 октября 2011

Попробуйте это:

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, вероятно, не оправдывало версию словаря, но это может быть эффективно для разреженных матриц. Весь этот пример будет проще, если вы создадите матричный класс, тогда вы сможете переключать реализации и смотреть, что лучше для вас. Удачи.

0 голосов
/ 06 октября 2011

Это не работает, потому что x не обязательно число (вы не говорите нам, что это такое).

Так что вам, вероятно, нужно написать собственную функцию суммирования, которая проверяет, является ли элемент x или чем-то еще (возможно, вам придется использовать isinstance(element, int) or isinstance(element, float)).

...