Skip to content

Commit 94ef8eb

Browse files
authored
Merge pull request #8 from dynamicslab/rename-sensorselector
Rename sensorselector
2 parents f6f5c04 + 6f91134 commit 94ef8eb

File tree

11 files changed

+89
-81
lines changed

11 files changed

+89
-81
lines changed

.github/workflows/run-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
pip install -r requirements-dev.txt
3636
- name: Test with pytest
3737
run: |
38-
py.test tests
38+
pytest tests
3939
# - name: Upload coverage to Codecov
4040
# uses: codecov/codecov-action@v1
4141
# with:

examples/basis_comparison.ipynb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,21 +199,21 @@
199199
"models = [\n",
200200
" (\n",
201201
" 'Identity',\n",
202-
" ps.SensorSelector(\n",
202+
" ps.SSPOR(\n",
203203
" n_sensors=n_sensors, \n",
204204
" basis=ps.basis.Identity(n_basis_modes=max_basis_modes)\n",
205205
" )\n",
206206
" ),\n",
207207
" (\n",
208208
" 'SVD',\n",
209-
" ps.SensorSelector(\n",
209+
" ps.SSPOR(\n",
210210
" n_sensors=n_sensors, \n",
211211
" basis=ps.basis.SVD(n_basis_modes=max_basis_modes)\n",
212212
" )\n",
213213
" ),\n",
214214
" (\n",
215215
" 'Random Projection',\n",
216-
" ps.SensorSelector(\n",
216+
" ps.SSPOR(\n",
217217
" n_sensors=n_sensors, \n",
218218
" basis=ps.basis.RandomProjection(n_basis_modes=max_basis_modes)\n",
219219
" )\n",
@@ -317,15 +317,15 @@
317317
"models = [\n",
318318
" (\n",
319319
" 'Identity',\n",
320-
" ps.SensorSelector(basis=ps.basis.Identity(n_basis_modes=n_basis_modes))\n",
320+
" ps.SSPOR(basis=ps.basis.Identity(n_basis_modes=n_basis_modes))\n",
321321
" ),\n",
322322
" (\n",
323323
" 'SVD',\n",
324-
" ps.SensorSelector(basis=ps.basis.SVD(n_basis_modes=n_basis_modes))\n",
324+
" ps.SSPOR(basis=ps.basis.SVD(n_basis_modes=n_basis_modes))\n",
325325
" ),\n",
326326
" (\n",
327327
" 'Random Projection',\n",
328-
" ps.SensorSelector(basis=ps.basis.RandomProjection(n_basis_modes=n_basis_modes))\n",
328+
" ps.SSPOR(basis=ps.basis.RandomProjection(n_basis_modes=n_basis_modes))\n",
329329
" ),\n",
330330
"]"
331331
]

examples/cost_constrained_qr.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"* Atmospheric dynamics (approximating the concentrations of different molecules based on measurements taken at only a few locations)\n",
1414
"* Sea-surface temperature (predicting the temperature at any point on the ocean based on the temperatures measured at various other points on the ocean)\n",
1515
"\n",
16-
"In other notebooks we have shown how one can use the `SensorSelector` class to pick optimal locations in which to place sensors to accomplish this task. But so far we have treated all sensor locations as being equally viable. What happens when some sensor locations are more expensive than others? For example, it might be ten times as costly to place and maintain a buoy measuring the sea-surface temperature in the middle of the Atlantic compared to one close to the coast.\n",
16+
"In other notebooks we have shown how one can use the `SSPOR` class to pick optimal locations in which to place sensors to accomplish this task. But so far we have treated all sensor locations as being equally viable. What happens when some sensor locations are more expensive than others? For example, it might be ten times as costly to place and maintain a buoy measuring the sea-surface temperature in the middle of the Atlantic compared to one close to the coast.\n",
1717
"\n",
1818
"The cost-constrained QR algorithm was devised specifically to solve such problems. The `PySensors` object implementing this method is named `CCQR` and in this notebook we'll demonstrate its use on a toy problem.\n",
1919
"\n",
@@ -274,7 +274,7 @@
274274
" basis = ps.basis.SVD(n_basis_modes=50)\n",
275275
" \n",
276276
" # Initialize and fit the model\n",
277-
" model = ps.SensorSelector(n_sensors=n_sensors, optimizer=optimizer)\n",
277+
" model = ps.SSPOR(n_sensors=n_sensors, optimizer=optimizer)\n",
278278
" model.fit(X_train)\n",
279279
" \n",
280280
" # Get average reconstruction error across test set\n",

examples/cross_validation.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@
141141
"source": [
142142
"from sklearn.model_selection import GridSearchCV\n",
143143
"\n",
144-
"model = ps.SensorSelector()\n",
144+
"model = ps.reconstruction.SSPOR()\n",
145145
"\n",
146146
"param_grid = {\n",
147147
" \"basis\": [ps.basis.Identity(), ps.basis.SVD(), ps.basis.RandomProjection()],\n",
@@ -333,7 +333,7 @@
333333
"from scipy.stats import randint\n",
334334
"from sklearn.model_selection import RandomizedSearchCV\n",
335335
"\n",
336-
"model = ps.SensorSelector(n_sensors=30)\n",
336+
"model = ps.reconstruction.SSPOR(n_sensors=30)\n",
337337
"\n",
338338
"param_distributions = {\n",
339339
" \"basis\": [ps.basis.Identity(), ps.basis.SVD(), ps.basis.RandomProjection()],\n",

examples/pysensors_overview.ipynb

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,11 @@
5454
"## Reconstruction\n",
5555
"For our reconstruction examples we will consider the Olivetti faces dataset from AT&T, consisting of 10 64-by-64 pictures of 40 different people. Each pixel will be treated as a sensor. An additional example performing sensor selection with `PySensors` to approximate global sea surface temperatures is given [here](https://github.com/dynamicslab/pysensors/blob/master/examples/sea_surface_temperature.ipynb)\n",
5656
"\n",
57-
"For reconstruction `PySensors` provides the `SensorSelector` class, which is largely based on the following paper ([link](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=8361090)):\n",
57+
"For reconstruction `PySensors` provides the `SSPOR` class (Sparse Sensor Placement Optimization for Reconstruction), which is largely based on the following paper ([link](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=8361090)):\n",
5858
"\n",
59-
" Manohar, Krithika, et al. \"Data-driven sparse sensor placement for reconstruction: Demonstrating the benefits of exploiting known patterns.\" IEEE Control Systems Magazine 38.3 (2018): 63-86."
59+
" Manohar, Krithika, et al. \"Data-driven sparse sensor placement for reconstruction: Demonstrating the benefits of exploiting known patterns.\" IEEE Control Systems Magazine 38.3 (2018): 63-86.\n",
60+
" \n",
61+
"`SSPOR` objects can be imported directly from `pysensors` or from `pysensors.reconstruction`."
6062
]
6163
},
6264
{
@@ -163,7 +165,7 @@
163165
"metadata": {},
164166
"source": [
165167
"### Simplest case\n",
166-
"A `SensorSelector` object is instantiated and fit to the data to obtain a ranking of sensors (technically sensor indices) in descending order of importance. We print the top 10 here."
168+
"A `SSPOR` object is instantiated and fit to the data to obtain a ranking of sensors (technically sensor indices) in descending order of importance. We print the top 10 here."
167169
]
168170
},
169171
{
@@ -185,7 +187,7 @@
185187
}
186188
],
187189
"source": [
188-
"model = ps.SensorSelector()\n",
190+
"model = ps.SSPOR()\n",
189191
"model.fit(X_train)\n",
190192
"\n",
191193
"# Ranked list of sensors\n",
@@ -238,8 +240,8 @@
238240
"metadata": {},
239241
"source": [
240242
"### Changing the number of sensors\n",
241-
"Since we didn't specify the number of sensors, `SensorSelector.get_selected_sensors()` returned them all.\n",
242-
"Instead we can pass in the desired number of sensors when instantiating a `SensorSelector` or after it has been fitted. Both options yield the same result."
243+
"Since we didn't specify the number of sensors, `SSPOR.get_selected_sensors()` returned them all.\n",
244+
"Instead we can pass in the desired number of sensors when instantiating a `SSPOR` object or after it has been fitted. Both options yield the same result."
243245
]
244246
},
245247
{
@@ -266,7 +268,7 @@
266268
"model.set_number_of_sensors(n_sensors)\n",
267269
"\n",
268270
"# Set number of sensors before fitting\n",
269-
"model_alt = ps.SensorSelector(n_sensors=n_sensors)\n",
271+
"model_alt = ps.SSPOR(n_sensors=n_sensors)\n",
270272
"model_alt.fit(X_train)\n",
271273
"\n",
272274
"print('Number of sensors originally returned:', len(ranked_sensors))\n",
@@ -280,7 +282,7 @@
280282
"metadata": {},
281283
"source": [
282284
"### Forming reconstructions\n",
283-
"Once a `SensorSelector` model has been fit to the data, it can be used to form reconstructions based on measurements from the selected sensor locations."
285+
"Once a `SSPOR` model has been fit to the data, it can be used to form reconstructions based on measurements from the selected sensor locations."
284286
]
285287
},
286288
{
@@ -317,7 +319,7 @@
317319
"source": [
318320
"# Fit the model\n",
319321
"n_sensors = 60\n",
320-
"model = ps.SensorSelector(n_sensors=n_sensors).fit(X_train)\n",
322+
"model = ps.SSPOR(n_sensors=n_sensors).fit(X_train)\n",
321323
"\n",
322324
"# Get the chosen sensor locations\n",
323325
"sensors = model.get_selected_sensors()\n",
@@ -368,7 +370,7 @@
368370
}
369371
],
370372
"source": [
371-
"model = ps.SensorSelector().fit(X_train)\n",
373+
"model = ps.SSPOR().fit(X_train)\n",
372374
"\n",
373375
"sensor_range = np.arange(1, 1000, 10)\n",
374376
"errors = model.reconstruction_error(X_test, sensor_range=sensor_range)\n",
@@ -435,7 +437,7 @@
435437
],
436438
"source": [
437439
"basis = ps.basis.SVD(n_basis_modes=n_basis_modes)\n",
438-
"model = ps.SensorSelector(basis=basis)\n",
440+
"model = ps.SSPOR(basis=basis)\n",
439441
"model.fit(X_train)\n",
440442
"\n",
441443
"# Ranked list of sensors\n",
@@ -472,7 +474,7 @@
472474
],
473475
"source": [
474476
"basis = ps.basis.RandomProjection(n_basis_modes=n_basis_modes)\n",
475-
"model = ps.SensorSelector(basis=basis)\n",
477+
"model = ps.SSPOR(basis=basis)\n",
476478
"model.fit(X_train)\n",
477479
"\n",
478480
"# Ranked list of sensors\n",
@@ -486,7 +488,7 @@
486488
"metadata": {},
487489
"source": [
488490
"#### Updating the number of basis modes\n",
489-
"The number of basis modes can be updated after a `SensorSelector` model has been fit via the `update_n_basis_modes` function.\n",
491+
"The number of basis modes can be updated after a `SSPOR` model has been fit via the `update_n_basis_modes` function.\n",
490492
"\n",
491493
"Note that when using `update_n_basis_modes` to *increase* the number of basis modes from the number specified when the model was fit requires one to pass in the training data. The number of basis modes can be decreased without the need for the training data."
492494
]
@@ -504,12 +506,12 @@
504506
"source": [
505507
"# Decreasing the number of basis modes\n",
506508
"basis = ps.basis.SVD(n_basis_modes=20)\n",
507-
"model = ps.SensorSelector(basis=basis).fit(X_train)\n",
509+
"model = ps.SSPOR(basis=basis).fit(X_train)\n",
508510
"model.update_n_basis_modes(10)\n",
509511
"\n",
510512
"# Increasing the number of basis modes\n",
511513
"basis = ps.basis.SVD(n_basis_modes=20)\n",
512-
"model = ps.SensorSelector(basis=basis).fit(X_train)\n",
514+
"model = ps.SSPOR(basis=basis).fit(X_train)\n",
513515
"model.update_n_basis_modes(30, x=X_train)"
514516
]
515517
},
@@ -587,7 +589,7 @@
587589
"\n",
588590
"# Fit the cost-constrained model\n",
589591
"optimizer = ps.optimizers.CCQR(sensor_costs=costs)\n",
590-
"model = ps.SensorSelector(optimizer=optimizer, n_sensors=n_sensors)\n",
592+
"model = ps.SSPOR(optimizer=optimizer, n_sensors=n_sensors)\n",
591593
"model.fit(X_train)\n",
592594
"\n",
593595
"# Visualize the top sensors\n",
@@ -607,7 +609,9 @@
607609
"\n",
608610
"`PySensors` implements the Sparse Sensor Placement Optimization for Classification (SSPOC) algorithm in the `SSPOC` class. See the original SSPOC paper for more information ([link](https://epubs.siam.org/doi/pdf/10.1137/15M1036713)):\n",
609611
"\n",
610-
" Brunton, Bingni W., et al. \"Sparse sensor placement optimization for classification.\" SIAM Journal on Applied Mathematics 76.5 (2016): 2099-2122."
612+
" Brunton, Bingni W., et al. \"Sparse sensor placement optimization for classification.\" SIAM Journal on Applied Mathematics 76.5 (2016): 2099-2122.\n",
613+
"\n",
614+
"`SSPOC` can be imported directly from `pysensors` or from `pysensors.classification`."
611615
]
612616
},
613617
{
@@ -621,7 +625,7 @@
621625
},
622626
"outputs": [],
623627
"source": [
624-
"from pysensors.classification import SSPOC"
628+
"from pysensors import SSPOC"
625629
]
626630
},
627631
{
@@ -843,7 +847,7 @@
843847
"metadata": {},
844848
"source": [
845849
"### Changing the basis\n",
846-
"Like the `SensorSelector` object, `SSPOC` instances accept a `basis` argument."
850+
"Like the `SSPOR` object, `SSPOC` instances accept a `basis` argument."
847851
]
848852
},
849853
{

examples/sea_surface_temperature.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"# Sea Surface Temperature (SST) sensors\n",
88
"This notebook demonstrates how to use `PySensors` to perform optimal sensor placement for the NOAA sea surface temperature (SST) dataset.\n",
99
"\n",
10-
"Given a set of snapshots of the sea surface temperature as training data, we would like to choose locations to place sensors that collectively allow us to predict (or reconstruct) the temperature at any other point on the ocean. We'll show how to use the `SensorSelector` class to efficiently solve this problem.\n",
10+
"Given a set of snapshots of the sea surface temperature as training data, we would like to choose locations to place sensors that collectively allow us to predict (or reconstruct) the temperature at any other point on the ocean. We'll show how to use the `SSPOR` class to efficiently solve this problem.\n",
1111
"\n",
1212
"See the following [paper](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=8361090) to learn about the mathematical background behind this approach:\n",
1313
"\n",
@@ -141,7 +141,7 @@
141141
"metadata": {},
142142
"source": [
143143
"## Optimal sensor placement\n",
144-
"Use a `SensorSelector` to determine optimal sensor locations, projecting the data onto 25 SVD modes. We select 25 sensors in this example."
144+
"Use a `SSPOR` instance to determine optimal sensor locations, projecting the data onto 25 SVD modes. We select 25 sensors in this example."
145145
]
146146
},
147147
{
@@ -155,7 +155,7 @@
155155
},
156156
"outputs": [],
157157
"source": [
158-
"model = ps.SensorSelector(\n",
158+
"model = ps.SSPOR(\n",
159159
" basis=ps.basis.SVD(n_basis_modes=25),\n",
160160
" n_sensors=25\n",
161161
")\n",

examples/vandermonde.ipynb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"import numpy as np\n",
2727
"from scipy.linalg import lstsq\n",
2828
"\n",
29-
"from pysensors import SensorSelector"
29+
"from pysensors.reconstruction import SSPOR"
3030
]
3131
},
3232
{
@@ -62,7 +62,7 @@
6262
"cell_type": "markdown",
6363
"metadata": {},
6464
"source": [
65-
"Next we feed this basis into a `SensorSelector` object, fit it to the basis, and ask it to select 10 sensor locations."
65+
"Next we feed this basis into a `SSPOR` object (Sparse Sensor Placement Optimization for Reconstruction), fit it to the basis, and ask it to select 10 sensor locations."
6666
]
6767
},
6868
{
@@ -84,7 +84,7 @@
8484
}
8585
],
8686
"source": [
87-
"model = SensorSelector(n_sensors=10)\n",
87+
"model = SSPOR(n_sensors=10)\n",
8888
"model.fit(X)\n",
8989
"sensors = model.get_selected_sensors()\n",
9090
"print(x[sensors])"
@@ -94,7 +94,7 @@
9494
"cell_type": "markdown",
9595
"metadata": {},
9696
"source": [
97-
"Let's define a (non-polynomial) function, sample it at a few points, and attempt to fit it with the monomial (Vandermonde) basis. We'll show that using measurements taken at the points suggested by the `SensorSelector` object will lead to a much better reconstruction than equi-spaced measurements."
97+
"Let's define a (non-polynomial) function, sample it at a few points, and attempt to fit it with the monomial (Vandermonde) basis. We'll show that using measurements taken at the points suggested by the `SSPOR` object will lead to a much better reconstruction than equi-spaced measurements."
9898
]
9999
},
100100
{
@@ -123,7 +123,7 @@
123123
},
124124
"outputs": [],
125125
"source": [
126-
"# Interpolation using the points selected by the SensorSelector\n",
126+
"# Interpolation using the points selected by the SSPOR\n",
127127
"pysense_interp = model.predict(f[sensors])"
128128
]
129129
},

pysensors/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66
except DistributionNotFound:
77
pass
88

9+
from .classification import SSPOC
10+
from .reconstruction import SSPOR
911

10-
from .pysensors import SensorSelector
1112

1213
__all__ = [
1314
# Modules:
1415
"basis",
1516
"classification",
17+
"reconstruction",
1618
"optimizers",
1719
"utils",
1820
# Non-modules:
19-
"SensorSelector",
21+
"SSPOR",
22+
"SSPOC",
2023
]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from ._sspor import SSPOR
2+
3+
__all__ = ["SSPOR"]

0 commit comments

Comments
 (0)