将矩阵与列向量进行比较
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.DataFrame
和pd.Series
、A
和B
A = pd.DataFrame([
[28, 39, 52],
[77, 80, 66],
[7, 18, 24],
[9, 97, 68]
])
B = pd.Series([32, 5, 42, 17])
pandas
默认情况下,当您比较 pd.DataFrame
和 pd.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 @EdChumnp.newaxis
是 None
的同义词。 np.newaxis is None
计算结果为 True
@piRSquared 啊..我不知道,我一直在这些情况下使用None
@EdChum 和大多数人一样,因为它少写了 6 个字符 :-)
@EdChum 我更喜欢这种方式,因为它更直观(意味着每次使用 newaxis
时我们将数组轴增加 1)并且可读性:)以上是关于将矩阵与列向量进行比较的主要内容,如果未能解决你的问题,请参考以下文章