dcekit 2.15.1__tar.gz → 2.17.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dcekit-2.15.1/dcekit.egg-info → dcekit-2.17.1}/PKG-INFO +1 -1
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/generative_model/__init__.py +2 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/generative_model/gmr.py +109 -4
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/generative_model/gtm.py +8 -7
- dcekit-2.17.1/dcekit/generative_model/ssgmr_xgmm.py +696 -0
- dcekit-2.17.1/dcekit/generative_model/ssgmr_xgmm_xma.py +65 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/generative_model/vbgmr.py +2 -2
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/variable_selection/basic_variable_selection.py +1 -1
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/variable_selection/variable_importance.py +12 -3
- {dcekit-2.15.1 → dcekit-2.17.1/dcekit.egg-info}/PKG-INFO +1 -1
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit.egg-info/SOURCES.txt +2 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/setup.py +1 -1
- {dcekit-2.15.1 → dcekit-2.17.1}/LICENSE +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/LICENSE.txt +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/MANIFEST.in +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/README.md +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/__init__.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/design_of_exmeriments/__init__.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/design_of_exmeriments/bayesian_optimization.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/just_in_time/__init__.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/just_in_time/jitpls.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/just_in_time/lwpls.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/learning/__init__.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/learning/ensemble_learning.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/learning/semi_supervised_learning.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/learning/transfer_learning.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/optimization/__init__.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/optimization/fast_opt_svr_hyperparams.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/optimization/iot.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/optimization/opt_dnn_hyperparams.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/optimization/opt_dnn_hyperparams_class.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/sampling/__init__.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/sampling/kennard_stone.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/validation/__init__.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/validation/applicability_domain.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/validation/metrics.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/validation/validation.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/variable_selection/__init__.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit/variable_selection/local_interpretation.py +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit.egg-info/dependency_links.txt +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit.egg-info/requires.txt +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/dcekit.egg-info/top_level.txt +0 -0
- {dcekit-2.15.1 → dcekit-2.17.1}/setup.cfg +0 -0
|
@@ -24,8 +24,10 @@ warnings.simplefilter('ignore')
|
|
|
24
24
|
class GMR(GaussianMixture):
|
|
25
25
|
|
|
26
26
|
def __init__(self, n_components=1, covariance_type='full', rep='mean',
|
|
27
|
+
weights_init=None, means_init=None, precisions_init=None,
|
|
27
28
|
max_iter=100, random_state=None, display_flag=False):
|
|
28
29
|
super(self.__class__, self).__init__(n_components=n_components, covariance_type=covariance_type,
|
|
30
|
+
weights_init=weights_init, means_init=means_init, precisions_init=precisions_init,
|
|
29
31
|
max_iter=max_iter, random_state=random_state)
|
|
30
32
|
|
|
31
33
|
self.rep = rep
|
|
@@ -123,9 +125,9 @@ class GMR(GaussianMixture):
|
|
|
123
125
|
"""
|
|
124
126
|
|
|
125
127
|
mode_of_estimated_mean, weighted_estimated_mean, _, _ = self.predict(dataset, numbers_of_input_variables, numbers_of_output_variables)
|
|
126
|
-
if self.rep == '
|
|
128
|
+
if self.rep == 'mode':
|
|
127
129
|
values = mode_of_estimated_mean.copy()
|
|
128
|
-
elif self.rep == '
|
|
130
|
+
elif self.rep == 'mean':
|
|
129
131
|
values = weighted_estimated_mean.copy()
|
|
130
132
|
return values
|
|
131
133
|
|
|
@@ -301,7 +303,6 @@ class GMR(GaussianMixture):
|
|
|
301
303
|
Parameters
|
|
302
304
|
----------
|
|
303
305
|
gmm_model: mixture.gaussian_mixture.GaussianMixture
|
|
304
|
-
GMM model constructed using scikit-learn
|
|
305
306
|
dataset: numpy.array or pandas.DataFrame
|
|
306
307
|
(autoscaled) m x n matrix of dataset of training data or test data,
|
|
307
308
|
m is the number of sammples and
|
|
@@ -363,6 +364,104 @@ class GMR(GaussianMixture):
|
|
|
363
364
|
l x m matrix of weights,
|
|
364
365
|
"""
|
|
365
366
|
|
|
367
|
+
dataset = np.array(dataset)
|
|
368
|
+
if dataset.ndim == 0:
|
|
369
|
+
dataset = np.reshape(dataset, (1, 1))
|
|
370
|
+
elif dataset.ndim == 1:
|
|
371
|
+
dataset = np.reshape(dataset, (1, dataset.shape[0]))
|
|
372
|
+
|
|
373
|
+
input_means = self.means_[:, numbers_of_input_variables]
|
|
374
|
+
output_means = self.means_[:, numbers_of_output_variables]
|
|
375
|
+
|
|
376
|
+
if self.covariance_type == 'full':
|
|
377
|
+
all_covariances = self.covariances_
|
|
378
|
+
elif self.covariance_type == 'diag':
|
|
379
|
+
all_covariances = np.empty(
|
|
380
|
+
[self.n_components, self.covariances_.shape[1], self.covariances_.shape[1]])
|
|
381
|
+
for component_number in range(self.n_components):
|
|
382
|
+
all_covariances[component_number, :, :] = np.diag(self.covariances_[component_number, :])
|
|
383
|
+
elif self.covariance_type == 'tied':
|
|
384
|
+
all_covariances = np.tile(self.covariances_, (self.n_components, 1, 1))
|
|
385
|
+
elif self.covariance_type == 'spherical':
|
|
386
|
+
all_covariances = np.empty([self.n_components, self.means_.shape[1], self.means_.shape[1]])
|
|
387
|
+
for component_number in range(self.n_components):
|
|
388
|
+
all_covariances[component_number, :, :] = np.diag(
|
|
389
|
+
self.covariances_[component_number] * np.ones(self.means_.shape[1]))
|
|
390
|
+
|
|
391
|
+
estimated_means = np.zeros([self.n_components, dataset.shape[0], len(numbers_of_output_variables)])
|
|
392
|
+
estimated_covariances = np.zeros([self.n_components, len(numbers_of_output_variables), len(numbers_of_output_variables)])
|
|
393
|
+
weights = np.zeros([self.n_components, dataset.shape[0]])
|
|
394
|
+
# print(all_covariances.shape[2], len(numbers_of_input_variables), len(numbers_of_output_variables))
|
|
395
|
+
if all_covariances.shape[2] == len(numbers_of_input_variables) + len(numbers_of_output_variables):
|
|
396
|
+
input_output_covariances = all_covariances[:, numbers_of_input_variables, :]
|
|
397
|
+
input_covariances = input_output_covariances[:, :, numbers_of_input_variables]
|
|
398
|
+
input_output_covariances = input_output_covariances[:, :, numbers_of_output_variables]
|
|
399
|
+
output_input_covariances = all_covariances[:, numbers_of_output_variables, :]
|
|
400
|
+
output_covariances = output_input_covariances[:, :, numbers_of_output_variables]
|
|
401
|
+
output_input_covariances = output_input_covariances[:, :, numbers_of_input_variables]
|
|
402
|
+
|
|
403
|
+
# estimated means and weights for all components
|
|
404
|
+
for component_number in range(self.n_components):
|
|
405
|
+
estimated_means[component_number, :, :] = output_means[component_number, :] + (
|
|
406
|
+
dataset - input_means[component_number, :]).dot(
|
|
407
|
+
np.linalg.inv(input_covariances[component_number, :, :])).dot(
|
|
408
|
+
input_output_covariances[component_number, :, :])
|
|
409
|
+
estimated_covariances[component_number, :, :] = output_covariances[component_number, :, :] - output_input_covariances[component_number, :, :].dot(
|
|
410
|
+
np.linalg.inv(input_covariances[component_number, :, :])).dot(input_output_covariances[component_number, :, :])
|
|
411
|
+
try:
|
|
412
|
+
weights[component_number, :] = self.weights_[component_number] * \
|
|
413
|
+
multivariate_normal.pdf(dataset,
|
|
414
|
+
input_means[component_number, :],
|
|
415
|
+
input_covariances[component_number, :, :])
|
|
416
|
+
except:
|
|
417
|
+
print('assignment of weights is failed, and zero is assigned')
|
|
418
|
+
|
|
419
|
+
if len(np.where(weights.sum(axis=0)==0)[0]) > 0:
|
|
420
|
+
weights = np.ones(weights.shape)
|
|
421
|
+
if np.isnan(weights.sum(axis=0)).any():
|
|
422
|
+
weights = np.ones(weights.shape)
|
|
423
|
+
if np.isinf(weights.sum(axis=0)).any():
|
|
424
|
+
weights = np.ones(weights.shape)
|
|
425
|
+
weights = weights / weights.sum(axis=0)
|
|
426
|
+
|
|
427
|
+
return estimated_means, estimated_covariances, weights
|
|
428
|
+
|
|
429
|
+
def predict_mog_pdf(self, dataset, numbers_of_input_variables, numbers_of_output_variables):
|
|
430
|
+
"""
|
|
431
|
+
Gaussian Mixture Regression (GMR) based on Gaussian Mixture Model (GMM)
|
|
432
|
+
|
|
433
|
+
Predict values of variables for forward analysis (regression) and inverse analysis. Predition results are given as mixture of Gaussians
|
|
434
|
+
|
|
435
|
+
Parameters
|
|
436
|
+
----------
|
|
437
|
+
gmm_model: mixture.gaussian_mixture.GaussianMixture
|
|
438
|
+
GMM model constructed using scikit-learn
|
|
439
|
+
dataset: numpy.array or pandas.DataFrame
|
|
440
|
+
(autoscaled) m x n matrix of dataset of training data or test data,
|
|
441
|
+
m is the number of sammples and
|
|
442
|
+
n is the number of input variables
|
|
443
|
+
When this is X-variables, it is forward analysis (regression) and
|
|
444
|
+
when this is Y-variables, it is inverse analysis
|
|
445
|
+
numbers_of_input_variables: list
|
|
446
|
+
vector of numbers of input variables
|
|
447
|
+
When this is numbers of X-variables, it is forward analysis (regression) and
|
|
448
|
+
when this is numbers of Y-variables, it is inverse analysis
|
|
449
|
+
numbers_of_output_variables: list
|
|
450
|
+
vector of numbers of output variables
|
|
451
|
+
When this is numbers of Y-variables, it is forward analysis (regression) and
|
|
452
|
+
when this is numbers of X-variables, it is inverse analysis
|
|
453
|
+
|
|
454
|
+
Returns
|
|
455
|
+
-------
|
|
456
|
+
estimated_means : numpy.array
|
|
457
|
+
(autoscaled) l x m x k matrix of output variables estimated for all components,
|
|
458
|
+
k is the number of output variables
|
|
459
|
+
estimated_covariances : numpy.array
|
|
460
|
+
(autoscaled) l x k x k variance-covariance matrix of output variables estimated for all components,
|
|
461
|
+
weights : numpy.array
|
|
462
|
+
l x m matrix of weights,
|
|
463
|
+
"""
|
|
464
|
+
|
|
366
465
|
dataset = np.array(dataset)
|
|
367
466
|
if dataset.ndim == 0:
|
|
368
467
|
dataset = np.reshape(dataset, (1, 1))
|
|
@@ -390,6 +489,9 @@ class GMR(GaussianMixture):
|
|
|
390
489
|
estimated_means = np.zeros([self.n_components, dataset.shape[0], len(numbers_of_output_variables)])
|
|
391
490
|
estimated_covariances = np.zeros([self.n_components, len(numbers_of_output_variables), len(numbers_of_output_variables)])
|
|
392
491
|
weights = np.zeros([self.n_components, dataset.shape[0]])
|
|
492
|
+
pdfs = np.zeros([self.n_components, dataset.shape[0]])
|
|
493
|
+
logpdfs = np.zeros([self.n_components, dataset.shape[0]])
|
|
494
|
+
|
|
393
495
|
# print(all_covariances.shape[2], len(numbers_of_input_variables), len(numbers_of_output_variables))
|
|
394
496
|
if all_covariances.shape[2] == len(numbers_of_input_variables) + len(numbers_of_output_variables):
|
|
395
497
|
input_output_covariances = all_covariances[:, numbers_of_input_variables, :]
|
|
@@ -412,6 +514,8 @@ class GMR(GaussianMixture):
|
|
|
412
514
|
multivariate_normal.pdf(dataset,
|
|
413
515
|
input_means[component_number, :],
|
|
414
516
|
input_covariances[component_number, :, :])
|
|
517
|
+
pdfs[component_number, :] = multivariate_normal.pdf(dataset, input_means[component_number, :], input_covariances[component_number, :, :])
|
|
518
|
+
logpdfs[component_number, :] = multivariate_normal.logpdf(dataset, input_means[component_number, :], input_covariances[component_number, :, :])
|
|
415
519
|
except:
|
|
416
520
|
print('assignment of weights is failed, and zero is assigned')
|
|
417
521
|
|
|
@@ -422,8 +526,9 @@ class GMR(GaussianMixture):
|
|
|
422
526
|
if np.isinf(weights.sum(axis=0)).any():
|
|
423
527
|
weights = np.ones(weights.shape)
|
|
424
528
|
weights = weights / weights.sum(axis=0)
|
|
529
|
+
ioe = -logsumexp(logpdfs, axis=0, b=weights)
|
|
425
530
|
|
|
426
|
-
return estimated_means, estimated_covariances, weights
|
|
531
|
+
return estimated_means, estimated_covariances, weights, pdfs, logpdfs, ioe
|
|
427
532
|
|
|
428
533
|
def cv_opt(self, dataset, numbers_of_input_variables, numbers_of_output_variables, covariance_types,
|
|
429
534
|
numbers_of_components, fold_number):
|
|
@@ -627,7 +627,7 @@ class GTM:
|
|
|
627
627
|
if bo_iter == 0: # 最初の試行ではD最適基準を計算
|
|
628
628
|
# D最適基準の計算
|
|
629
629
|
param_std = params_df.std(axis=0, ddof=1)
|
|
630
|
-
param_std[np.where(param_std == 0)[0]] = 1
|
|
630
|
+
param_std.iloc[np.where(param_std == 0)[0]] = 1
|
|
631
631
|
autoscaled_params_df = (params_df - params_df.mean(axis=0)) / param_std # 計算のために標準化
|
|
632
632
|
|
|
633
633
|
all_indexes = list(range(autoscaled_params_df.shape[0])) # indexを取得
|
|
@@ -748,7 +748,7 @@ class GTM:
|
|
|
748
748
|
for bo_sample_number in range(bo_number_of_selecting_samples):
|
|
749
749
|
# オートスケーリング
|
|
750
750
|
x_std = bo_x_data.std(axis=0, ddof=1)
|
|
751
|
-
x_std[np.where(x_std == 0)[0]] = 1
|
|
751
|
+
x_std.iloc[np.where(x_std == 0)[0]] = 1
|
|
752
752
|
autoscaled_bo_y_data = (bo_y_data - bo_y_data.mean()) / bo_y_data.std()
|
|
753
753
|
autoscaled_bo_x_data = (bo_x_data - bo_x_data.mean()) / x_std
|
|
754
754
|
autoscaled_bo_x_prediction = (bo_x_prediction - bo_x_data.mean()) / x_std
|
|
@@ -937,7 +937,7 @@ class GTM:
|
|
|
937
937
|
if bo_iter == 0: # 最初の試行ではD最適基準を計算
|
|
938
938
|
# D最適基準の計算
|
|
939
939
|
param_std = params_df.std(axis=0, ddof=1)
|
|
940
|
-
param_std[np.where(param_std == 0)[0]] = 1
|
|
940
|
+
param_std.iloc[np.where(param_std == 0)[0]] = 1
|
|
941
941
|
autoscaled_params_df = (params_df - params_df.mean(axis=0)) / param_std # 計算のために標準化
|
|
942
942
|
|
|
943
943
|
all_indexes = list(range(autoscaled_params_df.shape[0])) # indexを取得
|
|
@@ -1004,8 +1004,8 @@ class GTM:
|
|
|
1004
1004
|
else:
|
|
1005
1005
|
# k3nerror_of_gtm = 10 ** 100
|
|
1006
1006
|
k3nerror_of_gtm = (np.random.rand()/10 + 1) * 50
|
|
1007
|
-
|
|
1008
|
-
params_with_score_df['k3nerror score']
|
|
1007
|
+
|
|
1008
|
+
params_with_score_df.loc[selected_params_idx, 'k3nerror score'] = k3nerror_of_gtm # データの保存
|
|
1009
1009
|
|
|
1010
1010
|
if bo_display_flag:
|
|
1011
1011
|
print('Best k3n-error :', params_with_score_df['k3nerror score'].min())
|
|
@@ -1016,7 +1016,7 @@ class GTM:
|
|
|
1016
1016
|
break
|
|
1017
1017
|
|
|
1018
1018
|
# Bayesian optimization
|
|
1019
|
-
bo_x_data = bo_params_df.copy() # GP学習用データは
|
|
1019
|
+
bo_x_data = bo_params_df.copy() # GP学習用データはGTMの結果があるサンプル
|
|
1020
1020
|
bo_x_prediction = remaining_params_df.copy() # predictionは選択されていない(GMRの結果がない)サンプル
|
|
1021
1021
|
bo_y_data = params_with_score_df.loc[bo_params_df.index, 'k3nerror score'] # yはGMRのr2cv
|
|
1022
1022
|
|
|
@@ -1039,7 +1039,7 @@ class GTM:
|
|
|
1039
1039
|
for bo_sample_number in range(bo_number_of_selecting_samples):
|
|
1040
1040
|
# オートスケーリング
|
|
1041
1041
|
x_std = bo_x_data.std(axis=0, ddof=1)
|
|
1042
|
-
x_std[np.where(x_std == 0)[0]] = 1
|
|
1042
|
+
x_std.iloc[np.where(x_std == 0)[0]] = 1
|
|
1043
1043
|
autoscaled_bo_y_data = (bo_y_data - bo_y_data.mean()) / bo_y_data.std()
|
|
1044
1044
|
autoscaled_bo_x_data = (bo_x_data - bo_x_data.mean()) / x_std
|
|
1045
1045
|
autoscaled_bo_x_prediction = (bo_x_prediction - bo_x_data.mean()) / x_std
|
|
@@ -1125,6 +1125,7 @@ class GTM:
|
|
|
1125
1125
|
self.shape_of_rbf_centers = [shape_of_rbf_centers, shape_of_rbf_centers]
|
|
1126
1126
|
self.variance_of_rbfs = variance_of_rbfs
|
|
1127
1127
|
self.lambda_in_em_algorithm = lambda_in_em
|
|
1128
|
+
self.rep = 'mean'
|
|
1128
1129
|
self.k3nerror = params_with_score_df_best['k3nerror score']
|
|
1129
1130
|
if bo_display_flag:
|
|
1130
1131
|
self.display_flag = True
|
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@author: Hiromasa Kaneko
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# Semi-supervised Gaussian Mixture Regression with x-only GMM pretraining
|
|
7
|
+
# (ssGMR-xGMM)
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from sklearn.mixture import GaussianMixture
|
|
11
|
+
|
|
12
|
+
from .gmr import GMR
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_VALID_COVARIANCE_TYPES = ('full', 'diag', 'tied', 'spherical')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _as_2d_float_array(values, name, allow_one_dimensional=False):
|
|
19
|
+
"""Convert input data to a finite two-dimensional float array."""
|
|
20
|
+
array = np.asarray(values, dtype=float)
|
|
21
|
+
if array.ndim == 1 and allow_one_dimensional:
|
|
22
|
+
array = array.reshape(-1, 1)
|
|
23
|
+
if array.ndim != 2:
|
|
24
|
+
raise ValueError('{0} must be a two-dimensional array.'.format(name))
|
|
25
|
+
if array.shape[0] == 0 or array.shape[1] == 0:
|
|
26
|
+
raise ValueError('{0} must not be empty.'.format(name))
|
|
27
|
+
if not np.all(np.isfinite(array)):
|
|
28
|
+
raise ValueError('{0} contains NaN or infinite values.'.format(name))
|
|
29
|
+
return array
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _validate_variable_numbers(numbers, number_of_variables, name):
|
|
33
|
+
"""Validate variable-number lists used by DCEKit GMR."""
|
|
34
|
+
values = np.asarray(numbers, dtype=int).reshape(-1)
|
|
35
|
+
if values.size == 0:
|
|
36
|
+
raise ValueError('{0} must contain at least one variable number.'.format(name))
|
|
37
|
+
if np.unique(values).size != values.size:
|
|
38
|
+
raise ValueError('{0} contains duplicated variable numbers.'.format(name))
|
|
39
|
+
if np.any(values < 0) or np.any(values >= number_of_variables):
|
|
40
|
+
raise ValueError(
|
|
41
|
+
'{0} contains a variable number outside [0, {1}].'.format(
|
|
42
|
+
name, number_of_variables - 1
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
return values
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _make_symmetric_positive_definite(matrix, minimum_eigenvalue):
|
|
49
|
+
"""Symmetrize a matrix and clip its eigenvalues to a positive floor."""
|
|
50
|
+
matrix = np.asarray(matrix, dtype=float)
|
|
51
|
+
matrix = 0.5 * (matrix + matrix.T)
|
|
52
|
+
eigenvalues, eigenvectors = np.linalg.eigh(matrix)
|
|
53
|
+
eigenvalues = np.maximum(eigenvalues, minimum_eigenvalue)
|
|
54
|
+
matrix = (eigenvectors * eigenvalues).dot(eigenvectors.T)
|
|
55
|
+
return 0.5 * (matrix + matrix.T)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _stabilize_joint_covariance(
|
|
59
|
+
covariance_x, covariance_xy, covariance_y, minimum_eigenvalue):
|
|
60
|
+
"""
|
|
61
|
+
Construct a positive-definite block covariance while preserving the x and
|
|
62
|
+
y marginal covariance matrices. The cross-covariance is shrunk only when
|
|
63
|
+
required by the positive-definite constraint.
|
|
64
|
+
"""
|
|
65
|
+
covariance_x = _make_symmetric_positive_definite(
|
|
66
|
+
covariance_x, minimum_eigenvalue
|
|
67
|
+
)
|
|
68
|
+
covariance_y = _make_symmetric_positive_definite(
|
|
69
|
+
covariance_y, minimum_eigenvalue
|
|
70
|
+
)
|
|
71
|
+
covariance_xy = np.asarray(covariance_xy, dtype=float)
|
|
72
|
+
|
|
73
|
+
cholesky_x = np.linalg.cholesky(covariance_x)
|
|
74
|
+
cholesky_y = np.linalg.cholesky(covariance_y)
|
|
75
|
+
|
|
76
|
+
# The block matrix is positive definite if all singular values of
|
|
77
|
+
# Lx^-1 Sxy Ly^-T are smaller than one.
|
|
78
|
+
normalized_cross_covariance = np.linalg.solve(
|
|
79
|
+
cholesky_x, covariance_xy
|
|
80
|
+
)
|
|
81
|
+
normalized_cross_covariance = np.linalg.solve(
|
|
82
|
+
cholesky_y, normalized_cross_covariance.T
|
|
83
|
+
).T
|
|
84
|
+
singular_values = np.linalg.svd(
|
|
85
|
+
normalized_cross_covariance, compute_uv=False
|
|
86
|
+
)
|
|
87
|
+
largest_singular_value = (
|
|
88
|
+
singular_values[0] if singular_values.size else 0.0
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
cross_covariance_scaling = 1.0
|
|
92
|
+
maximum_allowed_singular_value = 1.0 - 1e-8
|
|
93
|
+
if largest_singular_value >= maximum_allowed_singular_value:
|
|
94
|
+
cross_covariance_scaling = (
|
|
95
|
+
maximum_allowed_singular_value / largest_singular_value
|
|
96
|
+
)
|
|
97
|
+
covariance_xy = covariance_xy * cross_covariance_scaling
|
|
98
|
+
|
|
99
|
+
number_of_x_variables = covariance_x.shape[0]
|
|
100
|
+
number_of_y_variables = covariance_y.shape[0]
|
|
101
|
+
covariance = np.zeros(
|
|
102
|
+
(number_of_x_variables + number_of_y_variables,
|
|
103
|
+
number_of_x_variables + number_of_y_variables),
|
|
104
|
+
dtype=float,
|
|
105
|
+
)
|
|
106
|
+
covariance[:number_of_x_variables, :number_of_x_variables] = covariance_x
|
|
107
|
+
covariance[:number_of_x_variables, number_of_x_variables:] = covariance_xy
|
|
108
|
+
covariance[number_of_x_variables:, :number_of_x_variables] = covariance_xy.T
|
|
109
|
+
covariance[number_of_x_variables:, number_of_x_variables:] = covariance_y
|
|
110
|
+
covariance = 0.5 * (covariance + covariance.T)
|
|
111
|
+
return covariance, cross_covariance_scaling
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _covariances_to_precisions(covariances, covariance_type):
|
|
115
|
+
"""Convert covariance parameters to the precisions_init representation."""
|
|
116
|
+
if covariance_type == 'full':
|
|
117
|
+
number_of_components, number_of_variables, _ = covariances.shape
|
|
118
|
+
identity = np.eye(number_of_variables)
|
|
119
|
+
precisions = np.empty_like(covariances)
|
|
120
|
+
for component_number in range(number_of_components):
|
|
121
|
+
precision = np.linalg.solve(
|
|
122
|
+
covariances[component_number], identity
|
|
123
|
+
)
|
|
124
|
+
precisions[component_number] = 0.5 * (
|
|
125
|
+
precision + precision.T
|
|
126
|
+
)
|
|
127
|
+
return precisions
|
|
128
|
+
if covariance_type == 'tied':
|
|
129
|
+
identity = np.eye(covariances.shape[0])
|
|
130
|
+
precision = np.linalg.solve(covariances, identity)
|
|
131
|
+
return 0.5 * (precision + precision.T)
|
|
132
|
+
if covariance_type in ('diag', 'spherical'):
|
|
133
|
+
return 1.0 / covariances
|
|
134
|
+
raise ValueError('Invalid covariance_type: {0}'.format(covariance_type))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _estimate_covariances_given_means(
|
|
138
|
+
dataset, responsibilities, effective_sample_sizes, means,
|
|
139
|
+
reg_covar, covariance_type):
|
|
140
|
+
"""
|
|
141
|
+
Estimate covariance parameters with means supplied externally.
|
|
142
|
+
|
|
143
|
+
This helper is also used by ssGMR-xGMM-xMA after replacing the x-side
|
|
144
|
+
means with their anchors.
|
|
145
|
+
"""
|
|
146
|
+
dataset = np.asarray(dataset, dtype=float)
|
|
147
|
+
responsibilities = np.asarray(responsibilities, dtype=float)
|
|
148
|
+
means = np.asarray(means, dtype=float)
|
|
149
|
+
number_of_samples, number_of_variables = dataset.shape
|
|
150
|
+
number_of_components = responsibilities.shape[1]
|
|
151
|
+
|
|
152
|
+
if covariance_type == 'full':
|
|
153
|
+
covariances = np.empty(
|
|
154
|
+
(number_of_components, number_of_variables, number_of_variables),
|
|
155
|
+
dtype=float,
|
|
156
|
+
)
|
|
157
|
+
for component_number in range(number_of_components):
|
|
158
|
+
centered_dataset = dataset - means[component_number]
|
|
159
|
+
covariance = (
|
|
160
|
+
centered_dataset.T * responsibilities[:, component_number]
|
|
161
|
+
).dot(centered_dataset) / effective_sample_sizes[component_number]
|
|
162
|
+
covariance = 0.5 * (covariance + covariance.T)
|
|
163
|
+
covariance.flat[::number_of_variables + 1] += reg_covar
|
|
164
|
+
covariances[component_number] = covariance
|
|
165
|
+
return covariances
|
|
166
|
+
|
|
167
|
+
if covariance_type == 'tied':
|
|
168
|
+
covariance = np.zeros(
|
|
169
|
+
(number_of_variables, number_of_variables), dtype=float
|
|
170
|
+
)
|
|
171
|
+
for component_number in range(number_of_components):
|
|
172
|
+
centered_dataset = dataset - means[component_number]
|
|
173
|
+
covariance += (
|
|
174
|
+
centered_dataset.T * responsibilities[:, component_number]
|
|
175
|
+
).dot(centered_dataset)
|
|
176
|
+
covariance /= responsibilities.sum()
|
|
177
|
+
covariance = 0.5 * (covariance + covariance.T)
|
|
178
|
+
covariance.flat[::number_of_variables + 1] += reg_covar
|
|
179
|
+
return covariance
|
|
180
|
+
|
|
181
|
+
if covariance_type == 'diag':
|
|
182
|
+
covariances = np.empty(
|
|
183
|
+
(number_of_components, number_of_variables), dtype=float
|
|
184
|
+
)
|
|
185
|
+
for component_number in range(number_of_components):
|
|
186
|
+
centered_dataset = dataset - means[component_number]
|
|
187
|
+
covariances[component_number] = (
|
|
188
|
+
responsibilities[:, component_number, np.newaxis]
|
|
189
|
+
* centered_dataset ** 2
|
|
190
|
+
).sum(axis=0) / effective_sample_sizes[component_number]
|
|
191
|
+
covariances += reg_covar
|
|
192
|
+
return covariances
|
|
193
|
+
|
|
194
|
+
if covariance_type == 'spherical':
|
|
195
|
+
covariances = np.empty(number_of_components, dtype=float)
|
|
196
|
+
for component_number in range(number_of_components):
|
|
197
|
+
centered_dataset = dataset - means[component_number]
|
|
198
|
+
covariances[component_number] = (
|
|
199
|
+
responsibilities[:, component_number]
|
|
200
|
+
* np.sum(centered_dataset ** 2, axis=1)
|
|
201
|
+
).sum() / (
|
|
202
|
+
effective_sample_sizes[component_number] * number_of_variables
|
|
203
|
+
)
|
|
204
|
+
covariances += reg_covar
|
|
205
|
+
return covariances
|
|
206
|
+
|
|
207
|
+
raise ValueError('Invalid covariance_type: {0}'.format(covariance_type))
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _compute_precision_cholesky(covariances, covariance_type):
|
|
211
|
+
"""
|
|
212
|
+
Compute precision Cholesky factors using scikit-learn's convention.
|
|
213
|
+
|
|
214
|
+
For full and tied covariances, the returned matrix is inv(L).T where
|
|
215
|
+
covariance = L L.T.
|
|
216
|
+
"""
|
|
217
|
+
if covariance_type == 'full':
|
|
218
|
+
number_of_components, number_of_variables, _ = covariances.shape
|
|
219
|
+
identity = np.eye(number_of_variables)
|
|
220
|
+
precision_cholesky = np.empty_like(covariances)
|
|
221
|
+
for component_number in range(number_of_components):
|
|
222
|
+
cholesky = np.linalg.cholesky(covariances[component_number])
|
|
223
|
+
precision_cholesky[component_number] = np.linalg.solve(
|
|
224
|
+
cholesky, identity
|
|
225
|
+
).T
|
|
226
|
+
return precision_cholesky
|
|
227
|
+
|
|
228
|
+
if covariance_type == 'tied':
|
|
229
|
+
number_of_variables = covariances.shape[0]
|
|
230
|
+
cholesky = np.linalg.cholesky(covariances)
|
|
231
|
+
return np.linalg.solve(cholesky, np.eye(number_of_variables)).T
|
|
232
|
+
|
|
233
|
+
if covariance_type in ('diag', 'spherical'):
|
|
234
|
+
if np.any(covariances <= 0):
|
|
235
|
+
raise ValueError('Covariances must be positive.')
|
|
236
|
+
return 1.0 / np.sqrt(covariances)
|
|
237
|
+
|
|
238
|
+
raise ValueError('Invalid covariance_type: {0}'.format(covariance_type))
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class SSGMRXGMM(GMR):
|
|
242
|
+
"""
|
|
243
|
+
Semi-supervised GMR with x-only GMM pretraining (ssGMR-xGMM).
|
|
244
|
+
|
|
245
|
+
A GMM is first fitted to x data that do not require corresponding y
|
|
246
|
+
measurements. Its weights, x-side means, and x-side covariance structure
|
|
247
|
+
are then used to initialize a joint GMM fitted to the labeled [x, y]
|
|
248
|
+
samples. After fitting, all prediction methods inherited from ``GMR`` can
|
|
249
|
+
be used for forward prediction and direct inverse analysis.
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
n_components : int, default=1
|
|
254
|
+
Number of Gaussian components.
|
|
255
|
+
covariance_type : {'full', 'diag', 'tied', 'spherical'}, default='full'
|
|
256
|
+
Covariance representation used in both the x-only and joint GMMs.
|
|
257
|
+
rep : {'mean', 'mode'}, default='mean'
|
|
258
|
+
Representative value returned by ``predict_rep``. ``'mode'`` selects
|
|
259
|
+
the conditional mean of the component with the largest responsibility;
|
|
260
|
+
``'mean'`` returns the responsibility-weighted conditional mean.
|
|
261
|
+
tol : float, default=1e-3
|
|
262
|
+
EM convergence tolerance.
|
|
263
|
+
reg_covar : float, default=1e-6
|
|
264
|
+
Non-negative regularization added to covariance diagonals.
|
|
265
|
+
max_iter : int, default=100
|
|
266
|
+
Maximum number of EM iterations for both GMM stages.
|
|
267
|
+
x_gmm_n_init : int, default=1
|
|
268
|
+
Number of initializations for the x-only GMM.
|
|
269
|
+
init_params : {'kmeans', 'k-means++', 'random', 'random_from_data'},
|
|
270
|
+
default='kmeans'
|
|
271
|
+
Initialization method for the x-only GMM.
|
|
272
|
+
random_state : int, RandomState or None, default=None
|
|
273
|
+
Random seed.
|
|
274
|
+
display_flag : bool, default=False
|
|
275
|
+
DCEKit-compatible display flag used by inherited utility methods.
|
|
276
|
+
responsibility_floor : float, default=1e-12
|
|
277
|
+
Small floor applied to x-only responsibilities before calculating
|
|
278
|
+
y-side initial values.
|
|
279
|
+
verbose : int, default=0
|
|
280
|
+
Verbosity passed to scikit-learn's GMM implementation.
|
|
281
|
+
verbose_interval : int, default=10
|
|
282
|
+
Interval between verbose messages.
|
|
283
|
+
|
|
284
|
+
Notes
|
|
285
|
+
-----
|
|
286
|
+
``labeled_dataset`` and ``x_for_pretraining`` must be expressed in exactly
|
|
287
|
+
the same x-variable scale and column order. The class intentionally does
|
|
288
|
+
not autoscale data, matching DCEKit's ``GMR`` behavior.
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
def __init__(
|
|
292
|
+
self, n_components=1, covariance_type='full', rep='mean',
|
|
293
|
+
tol=1e-3, reg_covar=1e-6, max_iter=100, x_gmm_n_init=1,
|
|
294
|
+
init_params='kmeans', random_state=None, display_flag=False,
|
|
295
|
+
responsibility_floor=1e-12, verbose=0, verbose_interval=10):
|
|
296
|
+
# GMR.__init__ currently uses super(self.__class__, self), which is not
|
|
297
|
+
# subclass-safe. Initialize GaussianMixture directly and inherit only
|
|
298
|
+
# GMR's regression/prediction methods.
|
|
299
|
+
GaussianMixture.__init__(
|
|
300
|
+
self,
|
|
301
|
+
n_components=n_components,
|
|
302
|
+
covariance_type=covariance_type,
|
|
303
|
+
tol=tol,
|
|
304
|
+
reg_covar=reg_covar,
|
|
305
|
+
max_iter=max_iter,
|
|
306
|
+
n_init=1,
|
|
307
|
+
init_params=init_params,
|
|
308
|
+
weights_init=None,
|
|
309
|
+
means_init=None,
|
|
310
|
+
precisions_init=None,
|
|
311
|
+
random_state=random_state,
|
|
312
|
+
warm_start=False,
|
|
313
|
+
verbose=verbose,
|
|
314
|
+
verbose_interval=verbose_interval,
|
|
315
|
+
)
|
|
316
|
+
self.rep = rep
|
|
317
|
+
self.x_gmm_n_init = x_gmm_n_init
|
|
318
|
+
self.display_flag = display_flag
|
|
319
|
+
self.responsibility_floor = responsibility_floor
|
|
320
|
+
|
|
321
|
+
def _check_method_parameters(self):
|
|
322
|
+
if self.covariance_type not in _VALID_COVARIANCE_TYPES:
|
|
323
|
+
raise ValueError(
|
|
324
|
+
'covariance_type must be one of {0}.'.format(
|
|
325
|
+
_VALID_COVARIANCE_TYPES
|
|
326
|
+
)
|
|
327
|
+
)
|
|
328
|
+
if self.rep not in ('mean', 'mode'):
|
|
329
|
+
raise ValueError("rep must be either 'mean' or 'mode'.")
|
|
330
|
+
if not isinstance(self.x_gmm_n_init, (int, np.integer)) \
|
|
331
|
+
or self.x_gmm_n_init < 1:
|
|
332
|
+
raise ValueError('x_gmm_n_init must be a positive integer.')
|
|
333
|
+
if self.responsibility_floor < 0:
|
|
334
|
+
raise ValueError('responsibility_floor must be non-negative.')
|
|
335
|
+
if self.reg_covar < 0:
|
|
336
|
+
raise ValueError('reg_covar must be non-negative.')
|
|
337
|
+
|
|
338
|
+
def _prepare_joint_fit(self):
|
|
339
|
+
"""Hook used by ssGMR-xGMM-xMA before joint EM starts."""
|
|
340
|
+
return None
|
|
341
|
+
|
|
342
|
+
def _build_initial_parameters(
|
|
343
|
+
self, labeled_dataset, x_labeled, y_labeled,
|
|
344
|
+
numbers_of_x, numbers_of_y):
|
|
345
|
+
number_of_components = self.n_components
|
|
346
|
+
number_of_variables = labeled_dataset.shape[1]
|
|
347
|
+
number_of_x_variables = len(numbers_of_x)
|
|
348
|
+
number_of_y_variables = len(numbers_of_y)
|
|
349
|
+
responsibilities = self.x_gmm_.predict_proba(x_labeled)
|
|
350
|
+
if self.responsibility_floor > 0:
|
|
351
|
+
responsibilities = np.maximum(
|
|
352
|
+
responsibilities, self.responsibility_floor
|
|
353
|
+
)
|
|
354
|
+
responsibilities /= responsibilities.sum(axis=1, keepdims=True)
|
|
355
|
+
effective_sample_sizes = responsibilities.sum(axis=0)
|
|
356
|
+
minimum_effective_sample_size = np.finfo(float).eps * 100
|
|
357
|
+
effective_sample_sizes = np.maximum(
|
|
358
|
+
effective_sample_sizes, minimum_effective_sample_size
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
initial_weights = np.asarray(self.x_gmm_.weights_, dtype=float).copy()
|
|
362
|
+
initial_weights /= initial_weights.sum()
|
|
363
|
+
|
|
364
|
+
initial_means = np.zeros(
|
|
365
|
+
(number_of_components, number_of_variables), dtype=float
|
|
366
|
+
)
|
|
367
|
+
initial_means[:, numbers_of_x] = self.x_gmm_.means_
|
|
368
|
+
initial_y_means = responsibilities.T.dot(y_labeled) \
|
|
369
|
+
/ effective_sample_sizes[:, np.newaxis]
|
|
370
|
+
initial_means[:, numbers_of_y] = initial_y_means
|
|
371
|
+
|
|
372
|
+
minimum_eigenvalue = max(
|
|
373
|
+
float(self.reg_covar), np.finfo(float).eps * 100
|
|
374
|
+
)
|
|
375
|
+
cross_covariance_scaling = np.ones(
|
|
376
|
+
number_of_components, dtype=float
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
if self.covariance_type == 'full':
|
|
380
|
+
initial_covariances = np.zeros(
|
|
381
|
+
(number_of_components, number_of_variables,
|
|
382
|
+
number_of_variables),
|
|
383
|
+
dtype=float,
|
|
384
|
+
)
|
|
385
|
+
for component_number in range(number_of_components):
|
|
386
|
+
sample_weights = responsibilities[:, component_number]
|
|
387
|
+
centered_x = (
|
|
388
|
+
x_labeled - self.x_gmm_.means_[component_number]
|
|
389
|
+
)
|
|
390
|
+
centered_y = (
|
|
391
|
+
y_labeled - initial_y_means[component_number]
|
|
392
|
+
)
|
|
393
|
+
covariance_y = (
|
|
394
|
+
centered_y.T * sample_weights
|
|
395
|
+
).dot(centered_y) / effective_sample_sizes[component_number]
|
|
396
|
+
covariance_y = _make_symmetric_positive_definite(
|
|
397
|
+
covariance_y, minimum_eigenvalue
|
|
398
|
+
)
|
|
399
|
+
covariance_xy = (
|
|
400
|
+
centered_x.T * sample_weights
|
|
401
|
+
).dot(centered_y) / effective_sample_sizes[component_number]
|
|
402
|
+
covariance, scaling = _stabilize_joint_covariance(
|
|
403
|
+
self.x_gmm_.covariances_[component_number],
|
|
404
|
+
covariance_xy,
|
|
405
|
+
covariance_y,
|
|
406
|
+
minimum_eigenvalue,
|
|
407
|
+
)
|
|
408
|
+
cross_covariance_scaling[component_number] = scaling
|
|
409
|
+
initial_covariances[component_number][
|
|
410
|
+
np.ix_(numbers_of_x, numbers_of_x)
|
|
411
|
+
] = covariance[
|
|
412
|
+
:number_of_x_variables, :number_of_x_variables
|
|
413
|
+
]
|
|
414
|
+
initial_covariances[component_number][
|
|
415
|
+
np.ix_(numbers_of_x, numbers_of_y)
|
|
416
|
+
] = covariance[
|
|
417
|
+
:number_of_x_variables, number_of_x_variables:
|
|
418
|
+
]
|
|
419
|
+
initial_covariances[component_number][
|
|
420
|
+
np.ix_(numbers_of_y, numbers_of_x)
|
|
421
|
+
] = covariance[
|
|
422
|
+
number_of_x_variables:, :number_of_x_variables
|
|
423
|
+
]
|
|
424
|
+
initial_covariances[component_number][
|
|
425
|
+
np.ix_(numbers_of_y, numbers_of_y)
|
|
426
|
+
] = covariance[
|
|
427
|
+
number_of_x_variables:, number_of_x_variables:
|
|
428
|
+
]
|
|
429
|
+
|
|
430
|
+
elif self.covariance_type == 'diag':
|
|
431
|
+
initial_covariances = np.zeros(
|
|
432
|
+
(number_of_components, number_of_variables), dtype=float
|
|
433
|
+
)
|
|
434
|
+
initial_covariances[:, numbers_of_x] = self.x_gmm_.covariances_
|
|
435
|
+
for component_number in range(number_of_components):
|
|
436
|
+
centered_y = (
|
|
437
|
+
y_labeled - initial_y_means[component_number]
|
|
438
|
+
)
|
|
439
|
+
y_variances = (
|
|
440
|
+
responsibilities[:, component_number, np.newaxis]
|
|
441
|
+
* centered_y ** 2
|
|
442
|
+
).sum(axis=0) / effective_sample_sizes[component_number]
|
|
443
|
+
initial_covariances[
|
|
444
|
+
component_number, numbers_of_y
|
|
445
|
+
] = np.maximum(y_variances, minimum_eigenvalue)
|
|
446
|
+
initial_covariances = np.maximum(
|
|
447
|
+
initial_covariances, minimum_eigenvalue
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
elif self.covariance_type == 'tied':
|
|
451
|
+
covariance_xy_all = np.zeros(
|
|
452
|
+
(number_of_components, number_of_x_variables,
|
|
453
|
+
number_of_y_variables),
|
|
454
|
+
dtype=float,
|
|
455
|
+
)
|
|
456
|
+
covariance_y_all = np.zeros(
|
|
457
|
+
(number_of_components, number_of_y_variables,
|
|
458
|
+
number_of_y_variables),
|
|
459
|
+
dtype=float,
|
|
460
|
+
)
|
|
461
|
+
for component_number in range(number_of_components):
|
|
462
|
+
sample_weights = responsibilities[:, component_number]
|
|
463
|
+
centered_x = (
|
|
464
|
+
x_labeled - self.x_gmm_.means_[component_number]
|
|
465
|
+
)
|
|
466
|
+
centered_y = (
|
|
467
|
+
y_labeled - initial_y_means[component_number]
|
|
468
|
+
)
|
|
469
|
+
covariance_xy_all[component_number] = (
|
|
470
|
+
centered_x.T * sample_weights
|
|
471
|
+
).dot(centered_y) / effective_sample_sizes[component_number]
|
|
472
|
+
covariance_y_all[component_number] = (
|
|
473
|
+
centered_y.T * sample_weights
|
|
474
|
+
).dot(centered_y) / effective_sample_sizes[component_number]
|
|
475
|
+
|
|
476
|
+
component_weights = effective_sample_sizes \
|
|
477
|
+
/ effective_sample_sizes.sum()
|
|
478
|
+
covariance_xy = np.tensordot(
|
|
479
|
+
component_weights, covariance_xy_all, axes=(0, 0)
|
|
480
|
+
)
|
|
481
|
+
covariance_y = np.tensordot(
|
|
482
|
+
component_weights, covariance_y_all, axes=(0, 0)
|
|
483
|
+
)
|
|
484
|
+
covariance, scaling = _stabilize_joint_covariance(
|
|
485
|
+
self.x_gmm_.covariances_, covariance_xy, covariance_y,
|
|
486
|
+
minimum_eigenvalue,
|
|
487
|
+
)
|
|
488
|
+
cross_covariance_scaling[:] = scaling
|
|
489
|
+
initial_covariances = np.zeros(
|
|
490
|
+
(number_of_variables, number_of_variables), dtype=float
|
|
491
|
+
)
|
|
492
|
+
initial_covariances[np.ix_(numbers_of_x, numbers_of_x)] = \
|
|
493
|
+
covariance[:number_of_x_variables, :number_of_x_variables]
|
|
494
|
+
initial_covariances[np.ix_(numbers_of_x, numbers_of_y)] = \
|
|
495
|
+
covariance[:number_of_x_variables, number_of_x_variables:]
|
|
496
|
+
initial_covariances[np.ix_(numbers_of_y, numbers_of_x)] = \
|
|
497
|
+
covariance[number_of_x_variables:, :number_of_x_variables]
|
|
498
|
+
initial_covariances[np.ix_(numbers_of_y, numbers_of_y)] = \
|
|
499
|
+
covariance[number_of_x_variables:, number_of_x_variables:]
|
|
500
|
+
|
|
501
|
+
else: # spherical
|
|
502
|
+
initial_covariances = np.zeros(number_of_components, dtype=float)
|
|
503
|
+
for component_number in range(number_of_components):
|
|
504
|
+
centered_y = (
|
|
505
|
+
y_labeled - initial_y_means[component_number]
|
|
506
|
+
)
|
|
507
|
+
y_variances = (
|
|
508
|
+
responsibilities[:, component_number, np.newaxis]
|
|
509
|
+
* centered_y ** 2
|
|
510
|
+
).sum(axis=0) / effective_sample_sizes[component_number]
|
|
511
|
+
initial_covariances[component_number] = (
|
|
512
|
+
number_of_x_variables
|
|
513
|
+
* self.x_gmm_.covariances_[component_number]
|
|
514
|
+
+ np.sum(y_variances)
|
|
515
|
+
) / number_of_variables
|
|
516
|
+
initial_covariances = np.maximum(
|
|
517
|
+
initial_covariances, minimum_eigenvalue
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
initial_precisions = _covariances_to_precisions(
|
|
521
|
+
initial_covariances, self.covariance_type
|
|
522
|
+
)
|
|
523
|
+
return (
|
|
524
|
+
initial_weights,
|
|
525
|
+
initial_means,
|
|
526
|
+
initial_covariances,
|
|
527
|
+
initial_precisions,
|
|
528
|
+
responsibilities,
|
|
529
|
+
effective_sample_sizes,
|
|
530
|
+
cross_covariance_scaling,
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
def fit(
|
|
534
|
+
self, labeled_dataset, x_for_pretraining=None,
|
|
535
|
+
numbers_of_x=None, numbers_of_y=None):
|
|
536
|
+
"""
|
|
537
|
+
Fit ssGMR-xGMM.
|
|
538
|
+
|
|
539
|
+
Parameters
|
|
540
|
+
----------
|
|
541
|
+
labeled_dataset : array-like of shape (n_labeled, n_x + n_y)
|
|
542
|
+
Paired, consistently scaled [x, y] samples used for the joint GMM.
|
|
543
|
+
x_for_pretraining : array-like of shape (n_pretraining, n_x), optional
|
|
544
|
+
x samples used by the x-only GMM. They may include the labeled x
|
|
545
|
+
samples, additional unlabeled x samples, and, in a transductive
|
|
546
|
+
protocol, target-domain test x samples. If omitted, the labeled x
|
|
547
|
+
samples are used.
|
|
548
|
+
numbers_of_x : array-like of int
|
|
549
|
+
Column numbers of x in ``labeled_dataset``.
|
|
550
|
+
numbers_of_y : array-like of int
|
|
551
|
+
Column numbers of y in ``labeled_dataset``.
|
|
552
|
+
|
|
553
|
+
Returns
|
|
554
|
+
-------
|
|
555
|
+
self : SSGMRXGMM
|
|
556
|
+
Fitted model.
|
|
557
|
+
"""
|
|
558
|
+
self._check_method_parameters()
|
|
559
|
+
labeled_dataset = _as_2d_float_array(
|
|
560
|
+
labeled_dataset, 'labeled_dataset'
|
|
561
|
+
)
|
|
562
|
+
number_of_variables = labeled_dataset.shape[1]
|
|
563
|
+
if numbers_of_x is None or numbers_of_y is None:
|
|
564
|
+
raise ValueError(
|
|
565
|
+
'numbers_of_x and numbers_of_y must both be specified.'
|
|
566
|
+
)
|
|
567
|
+
numbers_of_x = _validate_variable_numbers(
|
|
568
|
+
numbers_of_x, number_of_variables, 'numbers_of_x'
|
|
569
|
+
)
|
|
570
|
+
numbers_of_y = _validate_variable_numbers(
|
|
571
|
+
numbers_of_y, number_of_variables, 'numbers_of_y'
|
|
572
|
+
)
|
|
573
|
+
if np.intersect1d(numbers_of_x, numbers_of_y).size:
|
|
574
|
+
raise ValueError('numbers_of_x and numbers_of_y must not overlap.')
|
|
575
|
+
if not np.array_equal(
|
|
576
|
+
np.sort(np.r_[numbers_of_x, numbers_of_y]),
|
|
577
|
+
np.arange(number_of_variables)):
|
|
578
|
+
raise ValueError(
|
|
579
|
+
'numbers_of_x and numbers_of_y must jointly cover every '
|
|
580
|
+
'column of labeled_dataset.'
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
x_labeled = labeled_dataset[:, numbers_of_x]
|
|
584
|
+
y_labeled = labeled_dataset[:, numbers_of_y]
|
|
585
|
+
if x_for_pretraining is None:
|
|
586
|
+
x_for_pretraining = x_labeled
|
|
587
|
+
else:
|
|
588
|
+
x_for_pretraining = np.asarray(
|
|
589
|
+
x_for_pretraining, dtype=float
|
|
590
|
+
)
|
|
591
|
+
if x_for_pretraining.ndim == 1 and len(numbers_of_x) == 1:
|
|
592
|
+
x_for_pretraining = x_for_pretraining.reshape(-1, 1)
|
|
593
|
+
if x_for_pretraining.ndim != 2:
|
|
594
|
+
raise ValueError(
|
|
595
|
+
'x_for_pretraining must be a two-dimensional array.'
|
|
596
|
+
)
|
|
597
|
+
if x_for_pretraining.shape[1] == number_of_variables:
|
|
598
|
+
# Select x before the finite-value check so that a joint-style
|
|
599
|
+
# array may contain missing y values.
|
|
600
|
+
x_for_pretraining = x_for_pretraining[:, numbers_of_x]
|
|
601
|
+
elif x_for_pretraining.shape[1] != len(numbers_of_x):
|
|
602
|
+
raise ValueError(
|
|
603
|
+
'x_for_pretraining must have either {0} x columns or {1} '
|
|
604
|
+
'joint-data columns.'.format(
|
|
605
|
+
len(numbers_of_x), number_of_variables
|
|
606
|
+
)
|
|
607
|
+
)
|
|
608
|
+
x_for_pretraining = _as_2d_float_array(
|
|
609
|
+
x_for_pretraining, 'x_for_pretraining'
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
if labeled_dataset.shape[0] < self.n_components:
|
|
613
|
+
raise ValueError(
|
|
614
|
+
'The number of labeled samples must be at least '
|
|
615
|
+
'n_components.'
|
|
616
|
+
)
|
|
617
|
+
if x_for_pretraining.shape[0] < self.n_components:
|
|
618
|
+
raise ValueError(
|
|
619
|
+
'The number of x pretraining samples must be at least '
|
|
620
|
+
'n_components.'
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
self.numbers_of_x_ = numbers_of_x.copy()
|
|
624
|
+
self.numbers_of_y_ = numbers_of_y.copy()
|
|
625
|
+
self.number_of_x_variables_ = len(numbers_of_x)
|
|
626
|
+
self.number_of_y_variables_ = len(numbers_of_y)
|
|
627
|
+
|
|
628
|
+
self.x_gmm_ = GaussianMixture(
|
|
629
|
+
n_components=self.n_components,
|
|
630
|
+
covariance_type=self.covariance_type,
|
|
631
|
+
tol=self.tol,
|
|
632
|
+
reg_covar=self.reg_covar,
|
|
633
|
+
max_iter=self.max_iter,
|
|
634
|
+
n_init=self.x_gmm_n_init,
|
|
635
|
+
init_params=self.init_params,
|
|
636
|
+
random_state=self.random_state,
|
|
637
|
+
warm_start=False,
|
|
638
|
+
verbose=self.verbose,
|
|
639
|
+
verbose_interval=self.verbose_interval,
|
|
640
|
+
)
|
|
641
|
+
self.x_gmm_.fit(x_for_pretraining)
|
|
642
|
+
|
|
643
|
+
(
|
|
644
|
+
self.initial_weights_,
|
|
645
|
+
self.initial_means_,
|
|
646
|
+
self.initial_covariances_,
|
|
647
|
+
self.initial_precisions_,
|
|
648
|
+
self.x_responsibilities_for_labeled_samples_,
|
|
649
|
+
self.x_effective_sample_sizes_,
|
|
650
|
+
self.cross_covariance_scaling_,
|
|
651
|
+
) = self._build_initial_parameters(
|
|
652
|
+
labeled_dataset,
|
|
653
|
+
x_labeled,
|
|
654
|
+
y_labeled,
|
|
655
|
+
numbers_of_x,
|
|
656
|
+
numbers_of_y,
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
# GaussianMixture consumes these public initialization attributes.
|
|
660
|
+
self.weights_init = self.initial_weights_.copy()
|
|
661
|
+
self.means_init = self.initial_means_.copy()
|
|
662
|
+
self.precisions_init = np.array(
|
|
663
|
+
self.initial_precisions_, copy=True
|
|
664
|
+
)
|
|
665
|
+
self._prepare_joint_fit()
|
|
666
|
+
|
|
667
|
+
# Call GaussianMixture.fit directly to retain GMR's prediction methods
|
|
668
|
+
# while avoiding GMR.__init__'s subclassing issue.
|
|
669
|
+
GaussianMixture.fit(self, labeled_dataset)
|
|
670
|
+
return self
|
|
671
|
+
|
|
672
|
+
def fit_from_xy(self, x_labeled, y_labeled, x_for_pretraining=None):
|
|
673
|
+
"""
|
|
674
|
+
Convenience interface when x and y are supplied as separate arrays.
|
|
675
|
+
"""
|
|
676
|
+
x_labeled = _as_2d_float_array(
|
|
677
|
+
x_labeled, 'x_labeled', allow_one_dimensional=True
|
|
678
|
+
)
|
|
679
|
+
y_labeled = _as_2d_float_array(
|
|
680
|
+
y_labeled, 'y_labeled', allow_one_dimensional=True
|
|
681
|
+
)
|
|
682
|
+
if x_labeled.shape[0] != y_labeled.shape[0]:
|
|
683
|
+
raise ValueError(
|
|
684
|
+
'x_labeled and y_labeled must have the same number of samples.'
|
|
685
|
+
)
|
|
686
|
+
labeled_dataset = np.c_[x_labeled, y_labeled]
|
|
687
|
+
numbers_of_x = np.arange(x_labeled.shape[1])
|
|
688
|
+
numbers_of_y = np.arange(
|
|
689
|
+
x_labeled.shape[1], labeled_dataset.shape[1]
|
|
690
|
+
)
|
|
691
|
+
return self.fit(
|
|
692
|
+
labeled_dataset,
|
|
693
|
+
x_for_pretraining=x_for_pretraining,
|
|
694
|
+
numbers_of_x=numbers_of_x,
|
|
695
|
+
numbers_of_y=numbers_of_y,
|
|
696
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@author: Hiromasa Kaneko
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# Semi-supervised Gaussian Mixture Regression with x-only GMM pretraining
|
|
7
|
+
# and x-mean anchoring (ssGMR-xGMM-xMA)
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from .ssgmr_xgmm import (
|
|
12
|
+
SSGMRXGMM,
|
|
13
|
+
_compute_precision_cholesky,
|
|
14
|
+
_estimate_covariances_given_means,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SSGMRXGMMXMA(SSGMRXGMM):
|
|
19
|
+
"""
|
|
20
|
+
Semi-supervised GMR with x-only GMM pretraining and x-mean anchoring.
|
|
21
|
+
|
|
22
|
+
Initialization is identical to :class:`SSGMRXGMM`. During every M-step of
|
|
23
|
+
the joint-GMM EM algorithm, the x-side means are replaced by the x-only GMM
|
|
24
|
+
means. Mixture weights, y-side means, and all covariance parameters remain
|
|
25
|
+
trainable. The covariance update is calculated around the anchored means,
|
|
26
|
+
as specified by ssGMR-xGMM-xMA.
|
|
27
|
+
|
|
28
|
+
The constructor and ``fit`` interface are the same as ``SSGMRXGMM``.
|
|
29
|
+
After fitting, all prediction methods inherited from DCEKit's ``GMR`` can
|
|
30
|
+
be used for forward prediction and direct inverse analysis.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def _prepare_joint_fit(self):
|
|
34
|
+
self.x_mean_anchors_ = self.initial_means_[
|
|
35
|
+
:, self.numbers_of_x_
|
|
36
|
+
].copy()
|
|
37
|
+
|
|
38
|
+
def _m_step(self, dataset, log_responsibilities, xp=None):
|
|
39
|
+
"""M-step with hard anchoring of the x-side component means."""
|
|
40
|
+
dataset = np.asarray(dataset, dtype=float)
|
|
41
|
+
log_responsibilities = np.asarray(
|
|
42
|
+
log_responsibilities, dtype=float
|
|
43
|
+
)
|
|
44
|
+
responsibilities = np.exp(log_responsibilities)
|
|
45
|
+
effective_sample_sizes = responsibilities.sum(axis=0)
|
|
46
|
+
effective_sample_sizes += 10 * np.finfo(float).eps
|
|
47
|
+
|
|
48
|
+
self.weights_ = effective_sample_sizes \
|
|
49
|
+
/ effective_sample_sizes.sum()
|
|
50
|
+
means = responsibilities.T.dot(dataset) \
|
|
51
|
+
/ effective_sample_sizes[:, np.newaxis]
|
|
52
|
+
means[:, self.numbers_of_x_] = self.x_mean_anchors_
|
|
53
|
+
self.means_ = means
|
|
54
|
+
|
|
55
|
+
self.covariances_ = _estimate_covariances_given_means(
|
|
56
|
+
dataset,
|
|
57
|
+
responsibilities,
|
|
58
|
+
effective_sample_sizes,
|
|
59
|
+
self.means_,
|
|
60
|
+
self.reg_covar,
|
|
61
|
+
self.covariance_type,
|
|
62
|
+
)
|
|
63
|
+
self.precisions_cholesky_ = _compute_precision_cholesky(
|
|
64
|
+
self.covariances_, self.covariance_type
|
|
65
|
+
)
|
|
@@ -132,9 +132,9 @@ class VBGMR(BayesianGaussianMixture):
|
|
|
132
132
|
"""
|
|
133
133
|
|
|
134
134
|
mode_of_estimated_mean, weighted_estimated_mean, _, _ = self.predict(dataset, numbers_of_input_variables, numbers_of_output_variables)
|
|
135
|
-
if self.rep == '
|
|
135
|
+
if self.rep == 'mode':
|
|
136
136
|
values = mode_of_estimated_mean.copy()
|
|
137
|
-
elif self.rep == '
|
|
137
|
+
elif self.rep == 'mean':
|
|
138
138
|
values = weighted_estimated_mean.copy()
|
|
139
139
|
return values
|
|
140
140
|
|
|
@@ -103,7 +103,7 @@ def clustering_based_on_correlation_coefficients(x, threshold_of_r):
|
|
|
103
103
|
distance_in_x = 1 / r_in_x
|
|
104
104
|
|
|
105
105
|
# clustering
|
|
106
|
-
clustering = AgglomerativeClustering(n_clusters=None,
|
|
106
|
+
clustering = AgglomerativeClustering(n_clusters=None, metric='precomputed', compute_full_tree='auto',
|
|
107
107
|
distance_threshold=1 / threshold_of_r, linkage='complete')
|
|
108
108
|
clustering.fit(distance_in_x)
|
|
109
109
|
cluster_numbers = clustering.labels_
|
|
@@ -88,7 +88,11 @@ def cvpfi(
|
|
|
88
88
|
corr_variable_all = X[:, corr_variable_number].copy()
|
|
89
89
|
for sample_number in range(x_test.shape[0]):
|
|
90
90
|
if np.random.rand(1)[0] < target_x_corr[corr_variable_number]:
|
|
91
|
-
|
|
91
|
+
tmp = np.random.choice(corr_variable_all, 1, replace=replace)
|
|
92
|
+
if len(tmp)== 1:
|
|
93
|
+
x_test_shuffled[sample_number, corr_variable_number] = tmp[0]
|
|
94
|
+
else:
|
|
95
|
+
x_test_shuffled[sample_number, corr_variable_number] = tmp
|
|
92
96
|
|
|
93
97
|
estimated_y_test_shuffled = estimator_copy.predict(x_test_shuffled)
|
|
94
98
|
if y.ndim == 1:
|
|
@@ -115,11 +119,12 @@ def cvpfi(
|
|
|
115
119
|
accuracy_cv = accuracy_score(y, estimated_y_in_cv)
|
|
116
120
|
else:
|
|
117
121
|
accuracy_cv = accuracy_score(np.ravel(y), np.ravel(estimated_y_in_cv))
|
|
118
|
-
|
|
122
|
+
print(accuracy_cv)
|
|
119
123
|
for variable_number in range(X.shape[1]):
|
|
120
124
|
for n_repeat in range(n_repeats):
|
|
121
125
|
# print(accuracy_score(y, estimated_y_in_cv_shuffled[:, n_repeat, variable_number]))
|
|
122
126
|
if y.ndim == 1:
|
|
127
|
+
print(accuracy_score(y, estimated_y_in_cv_shuffled[:, n_repeat, variable_number]))
|
|
123
128
|
importances[variable_number, n_repeat] = accuracy_cv - accuracy_score(y, estimated_y_in_cv_shuffled[:, n_repeat, variable_number])
|
|
124
129
|
else:
|
|
125
130
|
importances[variable_number, n_repeat] = accuracy_cv - accuracy_score(np.ravel(y), np.ravel(estimated_y_in_cv_shuffled[:, :, n_repeat, variable_number]))
|
|
@@ -202,7 +207,11 @@ def cvpfi_gmr(
|
|
|
202
207
|
corr_variable_all = X[:, corr_variable_number].copy()
|
|
203
208
|
for sample_number in range(x_test.shape[0]):
|
|
204
209
|
if np.random.rand(1)[0] < target_x_corr[corr_variable_number]:
|
|
205
|
-
|
|
210
|
+
tmp = np.random.choice(corr_variable_all, 1, replace=replace)
|
|
211
|
+
if len(tmp)== 1:
|
|
212
|
+
x_test_shuffled[sample_number, corr_variable_number] = tmp[0]
|
|
213
|
+
else:
|
|
214
|
+
x_test_shuffled[sample_number, corr_variable_number] = tmp
|
|
206
215
|
estimated_y_in_cv_shuffled[fold_index==fold_number_in_outer_cv, :, n_repeat, variable_number] = estimator_copy.predict_rep(x_test_shuffled, numbers_of_x, numbers_of_y)
|
|
207
216
|
|
|
208
217
|
importances = np.zeros([X.shape[1], n_repeats])
|
|
@@ -14,6 +14,8 @@ dcekit/design_of_exmeriments/bayesian_optimization.py
|
|
|
14
14
|
dcekit/generative_model/__init__.py
|
|
15
15
|
dcekit/generative_model/gmr.py
|
|
16
16
|
dcekit/generative_model/gtm.py
|
|
17
|
+
dcekit/generative_model/ssgmr_xgmm.py
|
|
18
|
+
dcekit/generative_model/ssgmr_xgmm_xma.py
|
|
17
19
|
dcekit/generative_model/vbgmr.py
|
|
18
20
|
dcekit/just_in_time/__init__.py
|
|
19
21
|
dcekit/just_in_time/jitpls.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|