Умножение матрицы сил Pandas

Я хотел бы принудительно «ориентировать» матричное умножение с помощью Python Pandas, как между DataFrames против DataFrames, Dataframes против Series и Series против Series.

В качестве примера я попробовал следующий код:

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

Какие выходы: 5

Но я ожидаю этого:

[1 2
 2 4]

Pandas великолепен, но эта неспособность выполнять умножение матриц так, как я хочу, больше всего расстраивает, поэтому любая помощь будет очень признательна.

PS: я знаю, что Pandas пытается неявно использовать индекс, чтобы найти правильный способ вычисления матричного произведения, но, похоже, это поведение нельзя отключить!


person gaborous    schedule 08.04.2013    source источник
comment
Серия — это одномерный объект; его транспонирование есть (бессмысленное определение) самого себя. Даже в чистом виде a = np.array([1,2]); a.dot(a.T) даст 5. Почему бы просто не написать функцию -- silly_dot -- с использованием тех же a[:,None] приемов, которые вы использовали в numpy, чтобы получить желаемое поведение?   -  person DSM    schedule 09.04.2013
comment
Я не знаю о трюках с numpy, но даже если бы это сработало для Series, это не сработало бы для DataFrames. Я просто хотел бы, чтобы Pandas работала с умножением матриц, как в Octave, когда мне нужно: простое t'*t решило бы проблему в Octave. Почему не в пандах?   -  person gaborous    schedule 09.04.2013
comment
вам следует посетить эту страницу: scipy.org/, существует множество причин, почему * означает поэлементное умножение, а не скалярное произведение, но, как указывает DSM, вы можете создать функцию для эмуляции того, что вы ищете   -  person Jeff    schedule 09.04.2013
comment
Я никогда не говорил, что это глупо, что * выполняет поэлементное умножение (вы можете перечитать мой комментарий), но глупо, что в пандах нет способа точечного умножения без выравнивания индексов. Без умножения матриц векторизация просто невозможна (а создание собственной функции эмуляции только усугубит ситуацию).   -  person gaborous    schedule 09.04.2013
comment
Также было бы неплохо, чтобы pandas поддерживали это, чтобы вам не приходилось преобразовывать вниз в numpy, чем преобразовывать обратно в структуры pandas.   -  person Adam Hughes    schedule 11.11.2014


Ответы (3)


Любой, кто придет к этому сейчас, может захотеть рассмотреть: 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
person Brian Deignan    schedule 09.06.2020
comment
Спасибо, похоже, это действительно правильный современный способ умножения матриц. Я принимаю это как решение. - person gaborous; 09.06.2020

Здесь:

In [1]: import pandas

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

In [3]: np.outer(t, t)
Out[3]:
array([[1, 2],
       [2, 4]])
person Chang She    schedule 09.04.2013
comment
Отлично, работает отлично! Панды должны добавить .outer() к Series и DataFrames (даже если это означает потерю индексов в процессе, такая операция очень часто требуется!). - person gaborous; 09.04.2013
comment
Подождите: это действительно работает для примера, который я показал, но это не совсем решает весь вопрос: независимо от ориентации t (может быть t или транспонировать t), он всегда выводит один и тот же результат! Я хотел бы иметь возможность форсировать ориентацию, которую я хочу, а не просто внешний точечный продукт. - person gaborous; 09.04.2013
comment
почему бы вам не использовать точку против внешнего вместо транспонирования? Если вам действительно нужно, чтобы t рассматривался как двумерная матрица, вы должны делать то, что предлагает @DSM, и делать t = t[:, None] - person Chang She; 10.04.2013
comment
Поскольку я не всегда хочу делать точечное или внешнее произведение, иногда я ожидаю, что результат будет вектором (точка всегда выводит скаляр, а внешнее всегда матрица). - person gaborous; 06.05.2013

Решение найдено 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, я опубликую здесь свои выводы).

person gaborous    schedule 20.04.2013