chemotools 0.0.26__py3-none-any.whl → 0.0.28__py3-none-any.whl

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.
@@ -1,3 +1,3 @@
1
- from .index_scaler import IndexScaler
2
1
  from .min_max_scaler import MinMaxScaler
3
2
  from .norm_scaler import NormScaler
3
+ from .point_scaler import PointScaler
@@ -5,17 +5,26 @@ from sklearn.utils.validation import check_is_fitted
5
5
  from chemotools.utils.check_inputs import check_input
6
6
 
7
7
 
8
- class IndexScaler(OneToOneFeatureMixin, BaseEstimator, TransformerMixin):
8
+ class PointScaler(OneToOneFeatureMixin, BaseEstimator, TransformerMixin):
9
9
  """
10
- A transformer that scales the input data by the value at a given index.
10
+ A transformer that scales the input data by the intensity value at a given point.
11
+ The point can be specified by an index or by a wavenumber.
11
12
 
12
13
  Parameters
13
14
  ----------
14
- index : int, optional
15
- The index to scale the data by.
15
+ point : int,
16
+ The point to scale the data by. It can be an index or a wavenumber.
17
+
18
+ wavenumber : array-like, optional
19
+ The wavenumbers of the input data. If not provided, the indices will be used
20
+ instead. Default is None. If provided, the wavenumbers must be provided in
21
+ ascending order.
16
22
 
17
23
  Attributes
18
24
  ----------
25
+ point_index_ : int
26
+ The index of the point to scale the data by. It is 0 if the wavenumbers are not provided.
27
+
19
28
  n_features_in_ : int
20
29
  The number of features in the input data.
21
30
 
@@ -28,13 +37,14 @@ class IndexScaler(OneToOneFeatureMixin, BaseEstimator, TransformerMixin):
28
37
  Fit the transformer to the input data.
29
38
 
30
39
  transform(X, y=0, copy=True)
31
- Transform the input data by scaling by the value at a given index.
40
+ Transform the input data by scaling by the value at a given Point.
32
41
  """
33
- def __init__(self, index: int = 0):
34
- self.index = index
42
+ def __init__(self, point: int = 0, wavenumbers: np.ndarray = None):
43
+ self.point = point
44
+ self.wavenumbers = wavenumbers
35
45
 
36
46
 
37
- def fit(self, X: np.ndarray, y=None) -> "IndexScaler":
47
+ def fit(self, X: np.ndarray, y=None) -> "PointScaler":
38
48
  """
39
49
  Fit the transformer to the input data.
40
50
 
@@ -48,7 +58,7 @@ class IndexScaler(OneToOneFeatureMixin, BaseEstimator, TransformerMixin):
48
58
 
49
59
  Returns
50
60
  -------
51
- self : IndexScaler
61
+ self : PointScaler
52
62
  The fitted transformer.
53
63
  """
54
64
  # Check that X is a 2D array and has only finite values
@@ -60,11 +70,18 @@ class IndexScaler(OneToOneFeatureMixin, BaseEstimator, TransformerMixin):
60
70
  # Set the fitted attribute to True
61
71
  self._is_fitted = True
62
72
 
73
+ # Set the point index
74
+ if self.wavenumbers is None:
75
+ self.point_index_ = self.point
76
+ else:
77
+ self.point_index_ = self._find_index(self.point)
78
+
79
+
63
80
  return self
64
81
 
65
82
  def transform(self, X: np.ndarray, y=None) -> np.ndarray:
66
83
  """
67
- Transform the input data by scaling by the value at a given index.
84
+ Transform the input data by scaling by the value at a given Point.
68
85
 
69
86
  Parameters
70
87
  ----------
@@ -90,8 +107,12 @@ class IndexScaler(OneToOneFeatureMixin, BaseEstimator, TransformerMixin):
90
107
  if X_.shape[1] != self.n_features_in_:
91
108
  raise ValueError(f"Expected {self.n_features_in_} features but got {X_.shape[1]}")
92
109
 
93
- # Scale the data by index
110
+ # Scale the data by Point
94
111
  for i, x in enumerate(X_):
95
- X_[i] = x / x[self.index]
112
+ X_[i] = x / x[self.point_index_]
96
113
 
97
- return X_.reshape(-1, 1) if X_.ndim == 1 else X_
114
+ return X_.reshape(-1, 1) if X_.ndim == 1 else X_
115
+
116
+ def _find_index(self, target: float) -> int:
117
+ wavenumbers = np.array(self.wavenumbers)
118
+ return np.argmin(np.abs(wavenumbers - target))
@@ -1 +1,2 @@
1
- from .range_cut import RangeCut
1
+ from .range_cut import RangeCut
2
+ from .select_features import SelectFeatures
@@ -130,7 +130,5 @@ class RangeCut(OneToOneFeatureMixin, BaseEstimator, TransformerMixin):
130
130
  return X_[:, self.start_index_ : self.end_index_]
131
131
 
132
132
  def _find_index(self, target: float) -> int:
133
- if self.wavenumbers is None:
134
- return target
135
133
  wavenumbers = np.array(self.wavenumbers)
136
134
  return np.argmin(np.abs(wavenumbers - target))
@@ -0,0 +1,137 @@
1
+ import numpy as np
2
+ from sklearn.base import BaseEstimator, TransformerMixin, OneToOneFeatureMixin
3
+ from sklearn.utils.validation import check_is_fitted
4
+
5
+ from chemotools.utils.check_inputs import check_input
6
+
7
+
8
+ class SelectFeatures(OneToOneFeatureMixin, BaseEstimator, TransformerMixin):
9
+ """
10
+ A transformer that Selects the spectral data to a specified array of features. This
11
+ array can be continuous or discontinuous. The array of features is specified by:
12
+ - by the indices of the wavenumbers to select,
13
+ - by the wavenumbers to select, the wavenumbers must be provided to the transformer
14
+ when it is initialised. If the wavenumbers are not provided, the indices will be
15
+ used instead. The wavenumbers must be provided in ascending order.
16
+
17
+ Parameters
18
+ ----------
19
+ features : narray-like, optional
20
+ The index of the features to select. Default is None.
21
+
22
+ wavenumbers : array-like, optional
23
+ The wavenumbers of the input data. If not provided, the indices will be used
24
+ instead. Default is None. If provided, the wavenumbers must be provided in
25
+ ascending order.
26
+
27
+ Attributes
28
+ ----------
29
+ features_index_ : int
30
+ The index of the features to select.
31
+
32
+ n_features_in_ : int
33
+ The number of features in the input data.
34
+
35
+ _is_fitted : bool
36
+ Whether the transformer has been fitted to data.
37
+
38
+ Methods
39
+ -------
40
+ fit(X, y=None)
41
+ Fit the transformer to the input data.
42
+
43
+ transform(X, y=0, copy=True)
44
+ Transform the input data by cutting it to the specified range.
45
+ """
46
+
47
+ def __init__(
48
+ self,
49
+ features: np.ndarray = None,
50
+ wavenumbers: np.ndarray = None,
51
+ ):
52
+ self.features = features
53
+ self.wavenumbers = wavenumbers
54
+
55
+ def fit(self, X: np.ndarray, y=None) -> "SelectFeatures":
56
+ """
57
+ Fit the transformer to the input data.
58
+
59
+ Parameters
60
+ ----------
61
+ X : array-like of shape (n_samples, n_features)
62
+ The input data to fit the transformer to.
63
+
64
+ y : None
65
+ Ignored.
66
+
67
+ Returns
68
+ -------
69
+ self : SelectFeatures
70
+ The fitted transformer.
71
+ """
72
+ # Check that X is a 2D array and has only finite values
73
+ X = check_input(X)
74
+
75
+ # Set the number of features
76
+ self.n_features_in_ = X.shape[1]
77
+
78
+ # Set the fitted attribute to True
79
+ self._is_fitted = True
80
+
81
+ # Set the start and end indices
82
+ if self.features is None:
83
+ self.features_index_ = self.features
84
+ return self
85
+
86
+ if self.wavenumbers is None:
87
+ self.features_index_ = self.features
88
+ return self
89
+
90
+ self.features_index_ = self._find_indices()
91
+
92
+ return self
93
+
94
+ def transform(self, X: np.ndarray, y=None) -> np.ndarray:
95
+ """
96
+ Transform the input data by cutting it to the specified range.
97
+
98
+ Parameters
99
+ ----------
100
+ X : array-like of shape (n_samples, n_features)
101
+ The input data to transform.
102
+
103
+ y : None
104
+ Ignored.
105
+
106
+ Returns
107
+ -------
108
+ X_ : np.ndarray of shape (n_samples, n_features)
109
+ The transformed data.
110
+ """
111
+ # Check that the estimator is fitted
112
+ check_is_fitted(self, "_is_fitted")
113
+
114
+ # Check that X is a 2D array and has only finite values
115
+ X = check_input(X)
116
+ X_ = X.copy()
117
+
118
+ # Check that the number of features is the same as the fitted data
119
+ if X_.shape[1] != self.n_features_in_:
120
+ raise ValueError(
121
+ f"Expected {self.n_features_in_} features but got {X_.shape[1]}"
122
+ )
123
+
124
+ # Select the features
125
+ if self.features is None:
126
+ return X_
127
+
128
+ return X_[:, self.features_index_]
129
+
130
+ def _find_index(self, target: float) -> int:
131
+ if self.wavenumbers is None:
132
+ return target
133
+ wavenumbers = np.array(self.wavenumbers)
134
+ return np.argmin(np.abs(wavenumbers - target))
135
+
136
+ def _find_indices(self) -> np.ndarray:
137
+ return np.array([self._find_index(feature) for feature in self.features])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: chemotools
3
- Version: 0.0.26
3
+ Version: 0.0.28
4
4
  Summary: Package to integrate chemometrics in scikit-learn pipelines
5
5
  Home-page: https://github.com/paucablop/chemotools
6
6
  Author: Pau Cabaneros Lopez
@@ -2,15 +2,17 @@ chemotools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  chemotools/baseline/__init__.py,sha256=W61mEZU_9-sVGRkP2MJOIhd6e9KsOS1BYjxm1NOMIyM,373
3
3
  chemotools/baseline/air_pls.py,sha256=qn03l66IrxW7woFbRmRqCmfZHzQ7KKW8A7ogTxTHKo0,5443
4
4
  chemotools/baseline/ar_pls.py,sha256=OY2cpU2X6KIBR9ag3PAJXo_uQbniIV58zbUJxCxvZWs,4736
5
- chemotools/baseline/constant_baseline_correction.py,sha256=m6GKTAaCSjIjOK4Q3OHqdle5IyB4KFu04FzQofYt-oU,4221
5
+ chemotools/baseline/constant_baseline_correction.py,sha256=97xpKOBOwT5EhrD5tf32ZfkyZpf0_bL-VtyUFng1hn4,4158
6
6
  chemotools/baseline/cubic_spline_correction.py,sha256=PCHqR7TAhbdlTZrxgedlk0PU0kRUwQd_jymh0g-ieo8,3311
7
7
  chemotools/baseline/linear_correction.py,sha256=6Sw2n4QTvIDKWRdJpFD48hMvOEwqbctUAQLF1WwcoXs,3381
8
8
  chemotools/baseline/non_negative.py,sha256=17_82l95U9kgoQ3Pdz3-jGv8B51JzqPdHODt6PegWRw,2864
9
9
  chemotools/baseline/polynomial_correction.py,sha256=caP866fwZb7PASyz6oezgg8hdZtFMT0EimK89TGSTSc,4059
10
10
  chemotools/baseline/subtract_reference.py,sha256=Pht87XadXK0URq2fun66OHaUk_cx56AkF84ta3VJy_8,3441
11
- chemotools/datasets/__init__.py,sha256=yarhf-7bKB-mbStdWfi9LA_apOusoxY5A9bcwyzj10M,85
12
- chemotools/datasets/_base.py,sha256=ArZrVRW5m5yO13iK_EycvV8gheiWKR9hoSZCD_OfS1g,2249
11
+ chemotools/datasets/__init__.py,sha256=ojqxb-C_eDmizwUqVCJ8BqJxwULD7_hWCyVIA1uRO0c,116
12
+ chemotools/datasets/_base.py,sha256=Z174CaIlpx17Yu8Pg1qZPuHWkS3BYWn7gtOYsoe8zNk,2895
13
13
  chemotools/datasets/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ chemotools/datasets/data/coffee_labels.csv,sha256=ZXQWQIf8faLHjdnHfRoXfxMR56kq9Q1BGPZBkQyhGlY,487
15
+ chemotools/datasets/data/coffee_spectra.csv,sha256=VA-sN4u0hC5iALlRxxkj-K87Lz3b3mmUHBJPoDXychI,2206147
14
16
  chemotools/datasets/data/fermentation_hplc.csv,sha256=AMmiFQxwaXrH8aN310-3h1YQDiDrT8JNRv1RDvhEvg4,2140
15
17
  chemotools/datasets/data/fermentation_spectra.csv,sha256=MaaNMQP0lygJgFbEoUX0OUqdA-id8mF5Llvf_vj9tJk,15237508
16
18
  chemotools/datasets/data/train_hplc.csv,sha256=DjtmqiePOWB-F6TsOGFngE1pKyXkb7Xmsi-1CLxsTnE,249
@@ -18,10 +20,10 @@ chemotools/datasets/data/train_spectra.csv,sha256=iVF19W52NHlbqq8BbLomn8n47kSPT0
18
20
  chemotools/derivative/__init__.py,sha256=x2F0IJ-uCbEYFoXFbZl_RTPCbSq82vqGOwlM9R_2Klo,84
19
21
  chemotools/derivative/norris_william.py,sha256=JaJ7zlSiC_0tiITu7VWXtgKrmkQP7gLvuFb0_n1j9Dw,5081
20
22
  chemotools/derivative/savitzky_golay.py,sha256=fFzQRVGVXQIUkHp1x9dqfLVPlyStubIhSj9aGfZKuXY,3745
21
- chemotools/scale/__init__.py,sha256=qRDhHXhkwXrr0a9ctKVpjp8X8H8Wcu2pelavehv-8ik,115
22
- chemotools/scale/index_scaler.py,sha256=GsSVEfhVud-ZSVF7YwJBbix976W4a-1SXtbjUtQdqZ4,2661
23
+ chemotools/scale/__init__.py,sha256=HuXy_TktvXLTMWoW0pKhVCzMOkRkMRnvWCGiIKvjvZ8,115
23
24
  chemotools/scale/min_max_scaler.py,sha256=f1bGkODTWGwfnfMfWPimVxIZC3WIikgthQh-zUiaQUU,3123
24
25
  chemotools/scale/norm_scaler.py,sha256=qNs-npf5Jqcp8RYqt88_5-zwd-yIo-J1jItgUTFeozs,2699
26
+ chemotools/scale/point_scaler.py,sha256=LGSmZwuEYLxzVPgH-_aRk9SjOdmyQTxdguqRdBfqCwc,3540
25
27
  chemotools/scatter/__init__.py,sha256=M0_B4hXVoDc2Qx00QreUfhFqPUTs6LbU4CWaFU17hg4,288
26
28
  chemotools/scatter/extended_multiplicative_scatter_correction.py,sha256=J65hyEFBzKNo_35Ta9MKWO35CjTw-8hDbSr8xd8RIfc,6912
27
29
  chemotools/scatter/multiplicative_scatter_correction.py,sha256=MFemiwS-KWFOtlcXVhLnY4mn6QQ8pttuj6UP0rodXEM,5689
@@ -34,15 +36,16 @@ chemotools/smooth/savitzky_golay_filter.py,sha256=OlkW4-gHsgk7HFf7yeweKkL6aOZpNq
34
36
  chemotools/smooth/whittaker_smooth.py,sha256=OVEYEstsURgkLbjwRiBWeN_XNs_JOFeD60uyZsVtrHQ,3664
35
37
  chemotools/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
38
  chemotools/utils/check_inputs.py,sha256=fRAV4HIaGamdj_PNXSNnl7LurXytACNTGO51rhPpMUY,512
37
- chemotools/variable_selection/__init__.py,sha256=E5WmqGRkM6XgzmhTolP3Tu9KyCtEDk_Jcc1bEHvxVEg,31
38
- chemotools/variable_selection/range_cut.py,sha256=xNEnUJTdQeMnfeiOvX7BDo2ySZEoftRaI7BIsms_Mlo,4204
39
+ chemotools/variable_selection/__init__.py,sha256=6gKxCAoGKAOhhTerUyBg_62YKCIr0K4mbDcoDfbMJeA,75
40
+ chemotools/variable_selection/range_cut.py,sha256=1uH_nwYXEn_N1NY14n4uXpVvO6VVpM8zHea1cbHyZu4,4141
41
+ chemotools/variable_selection/select_features.py,sha256=pcoFmGZLUPjtRytGpnqK8YdVj3Z5hwKGSJ10VxCpg58,4164
39
42
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
43
  tests/fixtures.py,sha256=Xa-Vd62Kd1fyWg3PLUSP6iIkOK8etrbyOkMJTn3dvX8,1933
41
- tests/test_datasets.py,sha256=QwqZPLTcXG8f5ZeUJs5bq39v3kVnwSVxPRZ28spobUI,736
42
- tests/test_functionality.py,sha256=mR4gcHEWtzMCVbhsEzOCD2HfaSDO_fHosG6rcKanwYs,15568
43
- tests/test_sklearn_compliance.py,sha256=93RMkmqk4uhuz_wXIntPKCerxOxkQaAzJQwpDL57EaA,4593
44
- chemotools-0.0.26.dist-info/LICENSE,sha256=qtyOy2wDQVX9hxp58h3T-6Lmfv-mSCHoSRkcLUdM9bg,1070
45
- chemotools-0.0.26.dist-info/METADATA,sha256=gTNKoWiPNgbgoXWY8OGrLQgpY3sas-96ypUSjg0i9TM,5015
46
- chemotools-0.0.26.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
47
- chemotools-0.0.26.dist-info/top_level.txt,sha256=eNcNcKSdo-1H_2gwSDrS__dr7BM3R73Cnn-pBiW5FEw,17
48
- chemotools-0.0.26.dist-info/RECORD,,
44
+ tests/test_datasets.py,sha256=_3mMDYC-vUnb5BenMqvuhmkHI2PPIdsyq_nNu2ggH20,1055
45
+ tests/test_functionality.py,sha256=QKfFFy_0XBDH36BK8mnkG0-UIVcPXb9PQgiPmjfJrWA,17629
46
+ tests/test_sklearn_compliance.py,sha256=-DxSrJEK-sayGTYimTQFa4rJu93PtyBz91a5r5lCNXw,4773
47
+ chemotools-0.0.28.dist-info/LICENSE,sha256=qtyOy2wDQVX9hxp58h3T-6Lmfv-mSCHoSRkcLUdM9bg,1070
48
+ chemotools-0.0.28.dist-info/METADATA,sha256=WoCex9zO64rzBxbdK8WIVFE71ICyS1DY1w2CXc0aOvY,5015
49
+ chemotools-0.0.28.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
50
+ chemotools-0.0.28.dist-info/top_level.txt,sha256=eNcNcKSdo-1H_2gwSDrS__dr7BM3R73Cnn-pBiW5FEw,17
51
+ chemotools-0.0.28.dist-info/RECORD,,
tests/test_datasets.py CHANGED
@@ -1,6 +1,19 @@
1
1
  import pandas as pd
2
2
 
3
- from chemotools.datasets import load_fermentation_test, load_fermentation_train
3
+ from chemotools.datasets import load_coffee, load_fermentation_test, load_fermentation_train
4
+
5
+
6
+ def test_load_coffee():
7
+ # Arrange
8
+
9
+ # Act
10
+ coffee_spectra, coffee_labels = load_coffee()
11
+
12
+ # Assert
13
+ assert coffee_spectra.shape == (60, 1841)
14
+ assert coffee_labels.shape == (60, 1)
15
+ assert isinstance(coffee_spectra, pd.DataFrame)
16
+ assert isinstance(coffee_labels, pd.DataFrame)
4
17
 
5
18
 
6
19
  def test_load_fermentation_test():
@@ -10,7 +10,7 @@ from chemotools.baseline import (
10
10
  SubtractReference,
11
11
  )
12
12
  from chemotools.derivative import NorrisWilliams, SavitzkyGolay
13
- from chemotools.scale import IndexScaler, MinMaxScaler, NormScaler
13
+ from chemotools.scale import MinMaxScaler, NormScaler, PointScaler
14
14
  from chemotools.scatter import (
15
15
  ExtendedMultiplicativeScatterCorrection,
16
16
  MultiplicativeScatterCorrection,
@@ -18,7 +18,7 @@ from chemotools.scatter import (
18
18
  StandardNormalVariate,
19
19
  )
20
20
  from chemotools.smooth import MeanFilter, MedianFilter, WhittakerSmooth
21
- from chemotools.variable_selection import RangeCut
21
+ from chemotools.variable_selection import RangeCut, SelectFeatures
22
22
  from tests.fixtures import (
23
23
  spectrum,
24
24
  spectrum_arpls,
@@ -115,6 +115,19 @@ def test_extended_baseline_correction_with_weights():
115
115
  assert np.allclose(spectrum_emsc[0], reference, atol=1e-8)
116
116
 
117
117
 
118
+ def test_extended_baseline_correction_with_no_reference():
119
+ # Arrange
120
+ spectrum = np.array([1.0, 2.0, 3.0, 4.0, 5.0]).reshape(1, -1)
121
+
122
+ # Act
123
+ emsc = ExtendedMultiplicativeScatterCorrection(use_mean=False, use_median=False)
124
+
125
+ # Assert
126
+ with pytest.raises(ValueError):
127
+ emsc.fit_transform(spectrum)
128
+
129
+
130
+
118
131
  def test_extended_baseline_correction_with_wrong_reference():
119
132
  # Arrange
120
133
  spectrum = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]).reshape(
@@ -182,17 +195,6 @@ def test_extended_baseline_correction_through_msc_median(spectrum):
182
195
  assert np.allclose(spectrum_emsc[0], spectrum_msc, atol=1e-8)
183
196
 
184
197
 
185
- def test_index_scaler(spectrum):
186
- # Arrange
187
- index_scaler = IndexScaler(index=0)
188
- reference_spectrum = [value / spectrum[0][0] for value in spectrum[0]]
189
- # Act
190
- spectrum_corrected = index_scaler.fit_transform(spectrum)
191
-
192
- # Assert
193
- assert np.allclose(spectrum_corrected[0], reference_spectrum, atol=1e-8)
194
-
195
-
196
198
  def test_l1_norm(spectrum):
197
199
  # Arrange
198
200
  norm = 1
@@ -436,6 +438,31 @@ def test_norris_williams_wrong_filter():
436
438
  norris_williams_filter.fit_transform(array)
437
439
 
438
440
 
441
+ def test_point_scaler(spectrum):
442
+ # Arrange
443
+ index_scaler = PointScaler(point=0)
444
+ reference_spectrum = [value / spectrum[0][0] for value in spectrum[0]]
445
+
446
+ # Act
447
+ spectrum_corrected = index_scaler.fit_transform(spectrum)
448
+
449
+ # Assert
450
+ assert np.allclose(spectrum_corrected[0], reference_spectrum, atol=1e-8)
451
+
452
+
453
+ def test_point_scaler_with_wavenumbers():
454
+ # Arrange
455
+ wavenumbers = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
456
+ spectrum = np.array([[10.0, 12.0, 14.0, 16.0, 14.0, 12.0, 10.0, 12.0, 14.0, 16.0]])
457
+
458
+ # Act
459
+ index_scaler = PointScaler(point=4, wavenumbers=wavenumbers)
460
+ spectrum_corrected = index_scaler.fit_transform(spectrum)
461
+
462
+ # Assert
463
+ assert np.allclose(spectrum_corrected[0], spectrum[0] / spectrum[0][3], atol=1e-8)
464
+
465
+
439
466
  def test_range_cut_by_index(spectrum):
440
467
  # Arrange
441
468
  range_cut = RangeCut(start=0, end=10)
@@ -529,6 +556,47 @@ def test_saviszky_golay_filter_3():
529
556
  assert np.allclose(spectrum_corrected[0], np.ones((1, 10)), atol=1e-2)
530
557
 
531
558
 
559
+ def test_select_features():
560
+ # Arrange
561
+ spectrum = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]])
562
+
563
+ # Act
564
+ select_features = SelectFeatures()
565
+ spectrum_corrected = select_features.fit_transform(spectrum)
566
+
567
+ # Assert
568
+ assert np.allclose(spectrum_corrected[0], spectrum[0], atol=1e-8)
569
+
570
+
571
+ def test_select_features_with_index():
572
+ # Arrange
573
+ spectrum = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]])
574
+ expected = np.array([[1, 2, 3, 8, 9, 10]])
575
+
576
+ # Act
577
+ select_features = SelectFeatures(features=np.array([0, 1, 2, 7, 8, 9]))
578
+ spectrum_corrected = select_features.fit_transform(spectrum)
579
+
580
+ # Assert
581
+ assert np.allclose(spectrum_corrected[0], expected, atol=1e-8)
582
+
583
+
584
+ def test_select_features_with_wavenumbers():
585
+ # Arrange
586
+ wavenumbers = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0])
587
+ spectrum = np.array([[1.0, 2.0, 3.0, 5.0, 8.0, 13.0, 21.0, 34.0, 55.0, 89.0]])
588
+ expected = np.array([[1.0, 2.0, 3.0, 34.0, 55.0, 89.0]])
589
+
590
+ # Act
591
+ select_features = SelectFeatures(
592
+ features=np.array([1, 2, 3, 8, 9, 10]), wavenumbers=wavenumbers
593
+ )
594
+ spectrum_corrected = select_features.fit_transform(spectrum)
595
+
596
+ # Assert
597
+ assert np.allclose(spectrum_corrected[0], expected, atol=1e-8)
598
+
599
+
532
600
  def test_standard_normal_variate(spectrum, reference_snv):
533
601
  # Arrange
534
602
  snv = StandardNormalVariate()
@@ -11,7 +11,7 @@ from chemotools.baseline import (
11
11
  SubtractReference,
12
12
  )
13
13
  from chemotools.derivative import NorrisWilliams, SavitzkyGolay
14
- from chemotools.scale import IndexScaler, MinMaxScaler, NormScaler
14
+ from chemotools.scale import MinMaxScaler, NormScaler, PointScaler
15
15
  from chemotools.scatter import (
16
16
  ExtendedMultiplicativeScatterCorrection,
17
17
  MultiplicativeScatterCorrection,
@@ -24,7 +24,7 @@ from chemotools.smooth import (
24
24
  SavitzkyGolayFilter,
25
25
  WhittakerSmooth,
26
26
  )
27
- from chemotools.variable_selection import RangeCut
27
+ from chemotools.variable_selection import RangeCut, SelectFeatures
28
28
 
29
29
  from tests.fixtures import spectrum
30
30
 
@@ -68,13 +68,6 @@ def test_compliance_extended_multiplicative_scatter_correction():
68
68
  # Act & Assert
69
69
  check_estimator(transformer)
70
70
 
71
- # IndexScaler
72
- def test_compliance_index_scaler():
73
- # Arrange
74
- transformer = IndexScaler()
75
- # Act & Assert
76
- check_estimator(transformer)
77
-
78
71
 
79
72
  # LinearCorrection
80
73
  def test_compliance_linear_correction():
@@ -148,6 +141,14 @@ def test_compliance_norris_williams_2():
148
141
  check_estimator(transformer)
149
142
 
150
143
 
144
+ # PointScaler
145
+ def test_compliance_point_scaler():
146
+ # Arrange
147
+ transformer = PointScaler()
148
+ # Act & Assert
149
+ check_estimator(transformer)
150
+
151
+
151
152
  # PolynomialCorrection
152
153
  def test_compliance_polynomial_correction():
153
154
  # Arrange
@@ -172,6 +173,14 @@ def test_compliance_savitzky_golay_filter():
172
173
  check_estimator(transformer)
173
174
 
174
175
 
176
+ # SelectFeatures
177
+ def test_compliance_select_features():
178
+ # Arrange
179
+ transformer = SelectFeatures()
180
+ # Act & Assert
181
+ check_estimator(transformer)
182
+
183
+
175
184
  # StandardNormalVariate
176
185
  def test_compliance_standard_normal_variate():
177
186
  # Arrange