将矩阵与列向量进行比较

时间:2017-03-14 16:07:08

标签: python pandas numpy multidimensional-array numpy-ndarray

下面的数组'A'和向量'B'是pandas数据帧的一部分。

我有一个大型数组A

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

我的格式为B

32
5
42
17

我如何py的比较A的每一列与B.我试图获得A<的真/假值。 B比较得到以下结果:

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

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

4 个答案:

答案 0 :(得分:14)

考虑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是二维数组。为了比较BA,我们需要将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()

enter image description here

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

答案 1 :(得分:3)

更高效的是降低numpy级别(A,B是DataFrames):

A.values<B.values

答案 2 :(得分:3)

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

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 :(得分:2)

使用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转换为2D数组,以便在比较两个不同形状的数组时numpy可以广播。