矩阵孔理解

时间:2011-10-06 16:15:45

标签: python list list-comprehension

这是之前问题的一个分支,开始滚雪球。如果我有一个矩阵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 :(得分:0)

这不起作用,因为x不一定是数字(你不告诉我们它是什么)。

所以你可能需要编写自己的求和函数来检查项目是x还是其他东西(也许你必须使用isinstance(element, int) or isinstance(element, float))。

答案 1 :(得分:0)

average()中,在计算平均值之前,使用循环从x列表中删除所有lst.remove(x)值(您必须捕获错误remove()当它找不到它想要的东西时生成。

我建议使用像""之类的东西来代表洞,除非你已经有了一些东西。

答案 2 :(得分:0)

试试这个:

B = [(a[0], average(filter(lambda elt: elt != x, a[1:]))) for a in A]

使用ifilter中的itertools可以提高效果,尤其是对于大型矩阵。这可以在不更改average函数或修改A的情况下为您提供预期结果。


修改

如果矩阵稀疏,您可能需要考虑以不同方式实现矩阵。如果要保留当前的实现,则应使用值None来表示缺失值。这是与null相当的Python,您可能熟悉其他语言。

如何实现矩阵会大大改变您实现所需函数的方式,并且我将尝试覆盖您的方式以及可能对稀疏矩阵更有效的替代方法。

对于这两个我将使用带孔的示例矩阵:

# 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定义为仅返回填充值的生成器(iterable):

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。这里有一些优点,特别是如果矩阵中有很多孔,你不会浪费存储空间。这种方法的一个缺点是,根据你的构造方式创建矩阵可能会更加痛苦。

你的例子可能会变成(为了清晰起见空白):

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 codez可能没有做字典版本正义,但它对稀疏矩阵可能是有效的。如果您创建了一个矩阵类,那么整个示例会更容易,然后您可以切换实现并查看哪个更适合您。祝你好运。