"""
.. module:: CKernelHistIntersect
:synopsis: Histogram Intersection kernel
.. moduleauthor:: Battista Biggio <battista.biggio@unica.it>
.. moduleauthor:: Marco Melis <marco.melis@unica.it>
"""
from sklearn import metrics
import numpy as np
from secml.array import CArray
from secml.ml.kernel import CKernel
[docs]class CKernelHistIntersect(CKernel):
"""Histogram Intersection Kernel.
Given matrices X and Y, this is computed by::
K(x, y) = sum_i ( min(x[i], y[i]) )
for each pair of rows in X and in Y.
Attributes
----------
class_type : 'hist-intersect'
Parameters
----------
batch_size : int or None, optional
Size of the batch used for kernel computation. Default None.
.. deprecated:: 0.10
Examples
--------
>>> from secml.array import CArray
>>> from secml.ml.kernel.c_kernel_histintersect import CKernelHistIntersect
>>> print(CKernelHistIntersect().k(CArray([[1,2],[3,4]]), CArray([[10,20],[30,40]])))
CArray([[3. 3.]
[7. 7.]])
>>> print(CKernelHistIntersect().k(CArray([[1,2],[3,4]])))
CArray([[3. 3.]
[3. 7.]])
"""
__class_type = 'hist-intersect'
# TODO: ADD SPARSE SUPPORT
def _k(self, x, y):
"""Compute the histogram intersection kernel between x and y.
Parameters
----------
x : CArray or array_like
First array of shape (n_x, n_features).
y : CArray or array_like
Second array of shape (n_y, n_features).
Returns
-------
kernel : CArray
Kernel between x and y. Array of shape (n_x, n_y).
See Also
--------
:meth:`.CKernel.k` : Common computation interface for kernels.
"""
x = CArray(x).atleast_2d()
y = x if y is None else CArray(y).atleast_2d()
if x.issparse is True or y.issparse is True:
raise TypeError(
"Histogram-Intersection Kernel not available for sparse data.")
k = CArray.zeros(shape=(x.shape[0], y.shape[0]))
x_nd, y_nd = x.tondarray(), y.tondarray()
if x.shape[0] <= y.shape[0]: # loop on the matrix with less samples
# loop over samples in x, and compute x_i vs y
for i in range(k.shape[0]):
k[i, :] = CArray(np.minimum(x_nd[i, :], y_nd).sum(axis=1))
else:
# loop over samples in y, and compute y_j vs x
for j in range(k.shape[1]):
k[:, j] = CArray(np.minimum(x_nd, y_nd[j, :]).sum(axis=1)).T
return k
def _gradient(self, u, v):
"""Calculate Histogram Intersection kernel gradient wrt vector 'v'.
The kernel is computed between each row of u
(denoted with uk) and v, as::
sum_i ( min(uk[i], v[i]) )
The gradient computed w.r.t. v is thus
1 if v[i] < uk[i], and 0 elsewhere.
Parameters
----------
u : CArray or array_like
First array of shape (n_x, n_features).
v : CArray or array_like
Second array of shape (1, n_features).
Returns
-------
gradient : CArray
dK(u,v)/dv. Array of shape (n_x, n_features).
See Also
--------
:meth:`.CKernel.gradient` : Gradient computation interface for kernels.
"""
if v.issparse is True:
# Broadcasting not supported for sparse arrays
v_broadcast = v.repmat(u.shape[0], 1)
else: # Broadcasting is supported by design for dense arrays
v_broadcast = v
grad = CArray.zeros(shape=u.shape, sparse=v.issparse)
grad[v_broadcast < u] = 1
return grad