-
Notifications
You must be signed in to change notification settings - Fork 0
/
Loess.py
68 lines (52 loc) · 1.99 KB
/
Loess.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
def tricubic(x):
y = np.zeros_like(x)
idx = (x >= 0) & (x <= 1)
y[idx] = np.power(1.0 - np.power(np.abs(x[idx]), 3), 3)
return y
class Loess:
@staticmethod
def standarize_data(data):
data_mean = data.mean(0)
data_std = data.std(0)
return (data - data_mean) / data_std, data_mean, data_std
def __init__(self, xx, yy, degree):
xx = np.array(xx)
yy = np.array(yy)
self.s_xx, self.mean_xx, self.std_xx = self.standarize_data(xx)
self.s_yy, self.mean_yy, self.std_yy = self.standarize_data(yy)
self.degree = degree
def reset_xx(self, xx):
xx = np.array(xx)
self.s_xx, self.mean_xx, self.std_xx = self.standarize_data(xx)
def reset_yy(self, yy):
yy = np.array(yy)
self.s_yy, self.mean_yy, self.std_yy = self.standarize_data(yy)
def reset_degree(self, degree):
self.degree = degree
@staticmethod
def get_weights(distances, min_range):
max_distance = max(distances[min_range])
weights = tricubic(distances[min_range] / max_distance)
return weights
def standarize_x(self, value):
return (value - self.mean_xx) / self.std_xx
def destandarize_y(self, value):
return value * self.std_yy + self.mean_yy
def estimate(self, x, f):
q = int(len(self.s_xx) * f)
s_x = self.standarize_x(x)
distances = np.linalg.norm(self.s_xx - s_x, axis=1)
min_idx = np.argsort(distances)[:q]
weights = self.get_weights(distances, min_idx)
wm = np.diag(weights)
xm = self.s_xx[min_idx]
ym = self.s_yy[min_idx]
poly = PolynomialFeatures(degree=self.degree)
xm = poly.fit_transform(xm)
xp = poly.fit_transform(s_x.reshape(1, -1))[0]
xmt_wm = xm.T @ wm
beta = np.linalg.pinv(xmt_wm @ xm) @ xmt_wm @ ym
y = beta.T @ xp
return self.destandarize_y(y)[0]