**Note:** The Gower metric expects all continuous variables to have a standardized range. The default * range works for values that have been normalized between 0 and 1. * * References: * [1] J. C. Gower. (1971). A General Coefficient of Similarity and Some of Its Properties. * * @category Machine Learning * @package Rubix/ML * @author Andrew DalPino */ class Gower implements Distance, NaNSafe { /** * The range of the continuous feature columns. * * @var float */ protected $range; /** * @param float $range * @throws InvalidArgumentException */ public function __construct(float $range = 1.0) { if ($range <= 0.0) { throw new InvalidArgumentException('Range must be' . " greater than 0, $range given."); } $this->range = $range; } /** * Return the data types that this kernel is compatible with. * * @return DataType[] */ public function compatibility() : array { return [ DataType::categorical(), DataType::continuous(), ]; } /** * Compute the distance between two vectors. * * @param list $a * @param list $b * @return float */ public function compute(array $a, array $b) : float { $distance = 0.0; $numNaNs = 0; foreach ($a as $i => $valueA) { $valueB = $b[$i]; switch (true) { case is_float($valueA) and is_nan($valueA): ++$numNaNs; break; case is_float($valueB) and is_nan($valueB): ++$numNaNs; break; case !is_string($valueA) and !is_string($valueB): $distance += abs($valueA - $valueB) / $this->range; break; default: if ($valueA !== $valueB) { $distance += 1.0; } } } $n = count($a); if ($numNaNs === $n) { return NAN; } return $distance / ($n - $numNaNs); } /** * Return the string representation of the object. * * @return string */ public function __toString() : string { return "Gower (range: {$this->range})"; } }