【问题标题】:Pandas force matrix multiplicationPandas 强制矩阵乘法
【发布时间】:2013-04-08 22:16:21
【问题描述】:

我想在 DataFrames 与 DataFrames、Dataframes 与 Series 以及 Series 与 Series 之间使用 Python Pandas 强制矩阵乘法“方向”。

例如,我尝试了以下代码:

t = pandas.Series([1, 2])
print(t.T.dot(t))

哪个输出:5

但我希望这样:

[1 2
 2 4]

Pandas 很棒,但无法以我想要的方式进行矩阵乘法是最令人沮丧的,因此我们将不胜感激。

PS:我知道 Pandas 试图隐式使用索引来找到计算矩阵乘积的正确方法,但似乎无法关闭这种行为!

【问题讨论】:

  • 一个系列是一维对象;它的转置是(空洞地定义为)它自己。即使在纯 numpy 中,a = np.array([1,2]); a.dot(a.T) 也会给出5。为什么不简单地编写一个函数 -- silly_dot -- 使用与 numpy 中相同的 a[:,None] 技巧来提供您想要的行为?
  • 我不知道 numpy 技巧,但即使它适用于 Series,它也不适用于 DataFrames。我希望 Pandas 在需要时像在 Octave 中一样进行矩阵乘法:一个简单的 t'*t 可以解决 Octave 中的问题。为什么不在 Pandas 中?
  • 您应该查看此页面:scipy.org/…* 表示元素乘法而不是点积的原因有很多,但正如 DSM 指出的那样,您可以创建一个函数来模拟你正在寻找的东西
  • 我从来没有说过 * 进行元素乘法是愚蠢的(你可以重读我的评论),但很愚蠢的是,熊猫没有办法在没有索引对齐的情况下进行点乘。如果没有矩阵乘法,向量化是不可能的(创建我自己的仿真函数只会让事情变得更糟)。
  • 让 pandas 支持这一点也很好,这样您就不必向下转换为 numpy 而不是向上转换回 pandas 结构。

标签: python pandas matrix-multiplication dot-product dataframe


【解决方案1】:

这里:

In [1]: import pandas

In [2]: t = pandas.Series([1, 2])

In [3]: np.outer(t, t)
Out[3]:
array([[1, 2],
       [2, 4]])

【讨论】:

  • 完美,效果很好! Pandas 应该将 .outer() 添加到 Series 和 DataFrames 中(即使这意味着在过程中丢失索引,这种操作也经常需要!)。
  • 等等:它确实适用于我展示的示例,但它并不能完全解决整个问题:无论 t 的方向(可以是 t 或转置 t),它总是输出同样的结果!我希望能够强制我想要的方向,而不仅仅是外部点积。
  • 为什么不使用 dot vs outer 而不是转置呢?如果您确实需要将 t 视为二维矩阵,您应该按照@DSM 的建议执行 t = t[:, None]
  • 因为我并不总是想做点积或外积,所以有时我期望的结果是一个向量(点总是输出一个标量,而外总是一个矩阵)。
【解决方案2】:

现在来这里的任何人都可以考虑:pandas.Series.to_frame()。有点笨重。

这是原始问题的示例:

import pandas as pd

t = pd.Series([1, 2])

t.to_frame() @ t.to_frame().T
# or equivalently:
t.to_frame().dot(t.to_frame().T)

产量:

In [3]: t.to_frame().dot(t.to_frame().T)                                        
Out[3]: 
   0  1
0  1  2
1  2  4

【讨论】:

  • 谢谢,这似乎确实是进行矩阵乘法的正确现代方法。我接受它作为解决方案。
【解决方案3】:

y-p 找到的解决方案:

https://github.com/pydata/pandas/issues/3344#issuecomment-16533461

from pandas.util.testing import makeCustomDataframe as mkdf
a=mkdf(3,5,data_gen_f=lambda r,c: randint(1,100))
b=mkdf(5,3,data_gen_f=lambda r,c: randint(1,100))
c=DataFrame(a.values.dot(b.values),index=a.index,columns=b.columns)
print a
print b
print c
assert  (a.iloc[0,:].values*b.iloc[:,0].values.T).sum() == c.iloc[0,0]

C0       C_l0_g0  C_l0_g1  C_l0_g2  C_l0_g3  C_l0_g4
R0                                                  
R_l0_g0       39       87       88        2       65
R_l0_g1       59       14       76       10       65
R_l0_g2       93       69        4       29       58
C0       C_l0_g0  C_l0_g1  C_l0_g2
R0                                
R_l0_g0       76       88       11
R_l0_g1       66       73       47
R_l0_g2       78       69       15
R_l0_g3       47        3       40
R_l0_g4       54       31       31
C0       C_l0_g0  C_l0_g1  C_l0_g2
R0                                
R_l0_g0    19174    17876     7933
R_l0_g1    15316    13503     4862
R_l0_g2    16429    15382     7284

这里的断言没有用,它只是检查它确实是一个正确的矩阵乘法。

这里的关键似乎是第4行:

c=DataFrame(a.values.dot(b.values),index=a.index,columns=b.columns)

它的作用是计算 a 和 b 的点积,但强制生成的 DataFrame c 具有 a 的索引和 b 的列,实际上将点积转换为矩阵乘法,并且采用 pandas 的样式,因为您保留索引和列(您会丢失 a 的列和 b 的索引,但这在语义上是正确的,因为在矩阵乘法中您是对这些行求和,因此保留它们毫无意义)。

这有点尴尬,但如果它与 API 的其余部分保持一致,这似乎很简单(我仍然需要测试 Series x Dataframe 和 Series x Series 的结果,我将在这里发布我的发现)。

【讨论】:

    猜你喜欢
    • 2019-05-09
    • 2021-05-02
    • 2018-04-11
    • 2017-03-11
    • 2013-12-23
    • 2013-03-04
    • 2014-05-16
    • 2014-09-19
    相关资源
    最近更新 更多