将矩阵与列向量进行比较

Posted

技术标签:

【中文标题】将矩阵与列向量进行比较【英文标题】:Compare a matrix against a column vector 【发布时间】:2017-08-05 01:59:05 【问题描述】:

下面的数组“A”和向量“B”是 pandas 数据框的一部分。

我有一个大数组A 的形式:

28  39  52
77  80  66
7   18  24
9   97  68

我有一个向量B 的形式:

32
5
42
17

如何以 Python 方式比较 A 和 B 的每一列。我试图获取 A

TRUE    FALSE   FALSE
FALSE   FALSE   FALSE
TRUE    TRUE    TRUE
TRUE    FALSE   FALSE

我可以使用列表理解语法,但有没有更好的方法来解决这个问题。我的数组 A 和 B 非常大。

【问题讨论】:

【参考方案1】:

考虑pd.DataFramepd.SeriesAB

A = pd.DataFrame([
        [28, 39, 52],
        [77, 80, 66],
        [7, 18, 24],
        [9, 97, 68]
    ])

B = pd.Series([32, 5, 42, 17])

pandas

默认情况下,当您比较 pd.DataFramepd.Series 时,pandas 会将序列中的每个索引值与数据框的列名对齐。这就是您使用A < B 时发生的情况。在这种情况下,您的数据框中有 4 行,系列中有 4 个元素,因此我将假设您希望将系列的索引值与数据框的索引值对齐。为了指定要对齐的轴,您需要使用比较方法而不是运算符。那是因为在使用方法时,可以使用axis参数,并指定你想要axis=0而不是默认的axis=1

A.lt(B, axis=0)

       0      1      2
0   True  False  False
1  False  False  False
2   True   True   True
3   True  False  False

我经常把这个写成A.lt(B, 0)


numpy

在 numpy 中,您还必须注意数组的维度,您假设位置已经排好。如果位置来自同一个数据框,则会得到处理。

print(A.values)

[[28 39 52]
 [77 80 66]
 [ 7 18 24]
 [ 9 97 68]]

print(B.values)

[32  5 42 17]

请注意,B 是一维数组,而 A 是二维数组。为了沿着A 的行比较B,我们需要将B 重塑为一个二维数组。最明显的方法是使用reshape

print(A.values < B.values.reshape(4, 1))

[[ True False False]
 [False False False]
 [ True  True  True]
 [ True False False]]

但是,这些是您通常会看到其他人进行相同重塑的方式

A.values < B.values.reshape(-1, 1)

或者

A.values < B.values[:, None]

定时回测

为了掌握这些比较的速度,我构建了以下回溯测试。

def pd_cmp(df, s):
    return df.lt(s, 0)

def np_cmp_a2a(df, s):
    """To get an apples to apples comparison
    I return the same thing in both functions"""
    return pd.DataFrame(
        df.values < s.values[:, None],
        df.index, df.columns
    )

def np_cmp_a2o(df, s):
    """To get an apples to oranges comparison
    I return a numpy array"""
    return df.values < s.values[:, None]


results = pd.DataFrame(
    index=pd.Index([10, 1000, 100000], name='group size'),
    columns=pd.Index(['pd_cmp', 'np_cmp_a2a', 'np_cmp_a2o'], name='method'),
)

from timeit import timeit

for i in results.index:
    df = pd.concat([A] * i, ignore_index=True)
    s = pd.concat([B] * i, ignore_index=True)
    for j in results.columns:
        results.set_value(
            i, j,
            timeit(
                '(df, s)'.format(j),
                'from __main__ import , df, s'.format(j),
                number=100
            )
        )

results.plot()

我可以得出结论,基于numpy 的解决方案速度更快,但不是那么快。它们的比例都相同。

【讨论】:

由于 OP 表示数组非常大,因此对于未来的读者来说,黑白 Pandas 与 Numpy 的性能比较会提供很多信息 我真的很喜欢你的熊猫“timeit”包装器。【参考方案2】:

您可以使用lt 并在B 上调用squeeze 来执行此操作,以便将df 展平为一维系列:

In [107]:
A.lt(B.squeeze(),axis=0)

Out[107]:
       0      1      2
0   True  False  False
1  False  False  False
2   True   True   True
3   True  False  False

问题是如果没有squeeze,它会尝试对齐我们不想要的列标签。我们想沿列轴广播比较

【讨论】:

【参考方案3】:

更高效的是向下numpy级别(A,B在这里是DataFrames):

A.values<B.values

【讨论】:

【参考方案4】:

另一个使用 numpy 的选项是 numpy.newaxis

In [99]: B = B[:, np.newaxis]

In [100]: B
Out[100]: 
array([[32],
       [ 5],
       [42],
       [17]])

In [101]: A < B
Out[101]: 
array([[ True, False, False],
       [False, False, False],
       [ True,  True,  True],
       [ True, False, False]], dtype=bool)

本质上,我们将向量 B 转换为二维数组,以便 numpy 可以在比较两个不同形状的数组时进行广播。

【讨论】:

这很有用 不知道 np.newaxis +1 @EdChum np.newaxisNone 的同义词。 np.newaxis is None 计算结果为 True @piRSquared 啊..我不知道,我一直在这些情况下使用None @EdChum 和大多数人一样,因为它少写了 6 个字符 :-) @EdChum 我更喜欢这种方式,因为它更直观(意味着每次使用 newaxis 时我们将数组轴增加 1)并且可读性:)

以上是关于将矩阵与列向量进行比较的主要内容,如果未能解决你的问题,请参考以下文章

python Numpy库相关矩阵运算

行主要与列主要矩阵乘法

matlab中如何交换矩阵的行或者列

R:将列表中的所有数字与其自身进行比较并返回一个 TRUE/FALSE 矩阵

如何将列向量转换为 MxN 矩阵?

令矩阵每个元素四舍五入,使顺序高斯与列主元高斯结果不同