Skip to content

Commit

Permalink
Move h parameter of KDE from fit method to constructor (#692)
Browse files Browse the repository at this point in the history
* Move h parameter of KDE from fit method to constructor

* Fix JSDoc
  • Loading branch information
ishii-norimi authored Nov 18, 2023
1 parent 76a56b3 commit 7c2c560
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 9 deletions.
11 changes: 5 additions & 6 deletions lib/model/kernel_density_estimator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ export default class KernelDensityEstimator {
// https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%BC%E3%83%8D%E3%83%AB%E5%AF%86%E5%BA%A6%E6%8E%A8%E5%AE%9A
// http://ibis.t.u-tokyo.ac.jp/suzuki/lecture/2015/dataanalysis/L9.pdf
/**
* @param {number} [h=0] Smoothing parameter for the kernel
* @param {'gaussian' | 'rectangular' | 'triangular' | 'epanechnikov' | 'biweight' | 'triweight' | function (number): number} [kernel=gaussian] Kernel name
*/
constructor(kernel = 'gaussian') {
this._h = 0
constructor(h = 0, kernel = 'gaussian') {
this._h = h
if (typeof kernel === 'function') {
this._kernel = kernel
} else {
Expand Down Expand Up @@ -39,13 +40,11 @@ export default class KernelDensityEstimator {
* Fit model.
*
* @param {Array<Array<number>>} x Training data
* @param {number} h Smoothing parameter for the kernel
*/
fit(x, h = 0) {
fit(x) {
this._x = x

if (h > 0) {
this._h = h
if (this._h > 0) {
return
}

Expand Down
25 changes: 22 additions & 3 deletions tests/lib/model/kernel_density_estimator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,27 @@ import KernelDensityEstimator from '../../../lib/model/kernel_density_estimator.
import { correlation } from '../../../lib/evaluate/regression.js'

describe('density estimation', () => {
test('default', () => {
const model = new KernelDensityEstimator()
const n = 500
const x = Matrix.concat(Matrix.randn(n, 2, 0, 0.1), Matrix.randn(n, 2, 5, 0.1)).toArray()

model.fit(x)
const y = model.predict(x)
expect(y).toHaveLength(x.length)

const p = []
for (let i = 0; i < x.length; i++) {
const p1 = Math.exp(-x[i].reduce((s, v) => s + v ** 2, 0) / (2 * 0.1)) / (2 * Math.PI * 0.1)
const p2 = Math.exp(-x[i].reduce((s, v) => s + (v - 5) ** 2, 0) / (2 * 0.1)) / (2 * Math.PI * 0.1)
p[i] = (p1 + p2) / 2
}
const corr = correlation(y, p)
expect(corr).toBeGreaterThan(0.9)
})

test.each([undefined, 'gaussian', 'triangular', 'epanechnikov', 'biweight', 'triweight'])('kernel %s', kernel => {
const model = new KernelDensityEstimator(kernel)
const model = new KernelDensityEstimator(0, kernel)
const n = 500
const x = Matrix.concat(Matrix.randn(n, 2, 0, 0.1), Matrix.randn(n, 2, 5, 0.1)).toArray()

Expand All @@ -27,7 +46,7 @@ describe('density estimation', () => {
})

test.each(['rectangular'])('kernel %s', kernel => {
const model = new KernelDensityEstimator(kernel)
const model = new KernelDensityEstimator(0, kernel)
const n = 500
const x = Matrix.concat(Matrix.randn(n, 2, 0, 0.1), Matrix.randn(n, 2, 5, 0.1)).toArray()

Expand All @@ -46,7 +65,7 @@ describe('density estimation', () => {
})

test('custom kernel', () => {
const model = new KernelDensityEstimator(v => 1 / (v + 1.0e-8))
const model = new KernelDensityEstimator(1.0, v => 1 / (v + 1.0e-8))
const n = 500
const x = Matrix.concat(Matrix.randn(n, 2, 0, 0.1), Matrix.randn(n, 2, 5, 0.1)).toArray()

Expand Down

0 comments on commit 7c2c560

Please sign in to comment.