Мы должны умножить каждый элемент каждой строки попарно, мы можем сделать это как np.einsum('ij,ik->ijk, x, x)
. Это в 2 раза больше, но все же в 2 раза быстрее, чем PolynomialFeatures
.
import numpy as np
def interaction(x):
"""
>>> a = np.arange(9).reshape(3, 3)
>>> b = np.arange(6).reshape(3, 2)
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> interaction(a)
array([[ 0, 1, 2, 0, 0, 2],
[ 3, 4, 5, 12, 15, 20],
[ 6, 7, 8, 42, 48, 56]])
>>> b
array([[0, 1],
[2, 3],
[4, 5]])
>>> interaction(b)
array([[ 0, 1, 0],
[ 2, 3, 6],
[ 4, 5, 20]])
"""
b = np.einsum('ij,ik->ijk', x, x)
m, n = x.shape
axis1, axis2 = np.triu_indices(n, 1)
axis1 = np.tile(axis1, m)
axis2 = np.tile(axis2, m)
axis0 = np.arange(m).repeat(n * (n - 1) // 2)
return np.c_[x, b[axis0, axis1, axis2].reshape(m, -1)]
Сравнение производительности:
c = np.arange(30).reshape(6, 5)
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(2, interaction_only=True)
skl = poly.fit_transform
print(np.allclose(interaction(c), skl(c)[:, 1:]))
# True
In [1]: %timeit interaction(c)
118 µs ± 172 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [2]: %timeit skl(c)
243 µs ± 4.69 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)