deepecho 0.5.0.dev0__tar.gz → 0.6.0.dev0__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.
Files changed (35) hide show
  1. deepecho-0.6.0.dev0/PKG-INFO +241 -0
  2. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/__init__.py +1 -1
  3. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/models/base.py +25 -8
  4. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/models/basic_gan.py +23 -15
  5. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/models/par.py +63 -44
  6. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/sequences.py +13 -12
  7. deepecho-0.6.0.dev0/deepecho.egg-info/PKG-INFO +241 -0
  8. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho.egg-info/SOURCES.txt +2 -13
  9. deepecho-0.6.0.dev0/deepecho.egg-info/requires.txt +46 -0
  10. deepecho-0.6.0.dev0/pyproject.toml +205 -0
  11. deepecho-0.6.0.dev0/setup.cfg +4 -0
  12. deepecho-0.6.0.dev0/tests/test_tasks.py +39 -0
  13. deepecho-0.5.0.dev0/AUTHORS.rst +0 -1
  14. deepecho-0.5.0.dev0/CONTRIBUTING.rst +0 -237
  15. deepecho-0.5.0.dev0/HISTORY.md +0 -92
  16. deepecho-0.5.0.dev0/MANIFEST.in +0 -12
  17. deepecho-0.5.0.dev0/PKG-INFO +0 -302
  18. deepecho-0.5.0.dev0/deepecho.egg-info/PKG-INFO +0 -302
  19. deepecho-0.5.0.dev0/deepecho.egg-info/not-zip-safe +0 -1
  20. deepecho-0.5.0.dev0/deepecho.egg-info/requires.txt +0 -61
  21. deepecho-0.5.0.dev0/setup.cfg +0 -76
  22. deepecho-0.5.0.dev0/setup.py +0 -117
  23. deepecho-0.5.0.dev0/tests/__init__.py +0 -1
  24. deepecho-0.5.0.dev0/tests/integration/__init__.py +0 -1
  25. deepecho-0.5.0.dev0/tests/integration/test_basic_gan.py +0 -134
  26. deepecho-0.5.0.dev0/tests/integration/test_par.py +0 -156
  27. deepecho-0.5.0.dev0/tests/unit/__init__.py +0 -1
  28. deepecho-0.5.0.dev0/tests/unit/test_sequences.py +0 -255
  29. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/LICENSE +0 -0
  30. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/README.md +0 -0
  31. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/data/demo.csv +0 -0
  32. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/demo.py +0 -0
  33. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/models/__init__.py +0 -0
  34. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho.egg-info/dependency_links.txt +0 -0
  35. {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho.egg-info/top_level.txt +0 -0
@@ -0,0 +1,241 @@
1
+ Metadata-Version: 2.1
2
+ Name: deepecho
3
+ Version: 0.6.0.dev0
4
+ Summary: Create sequential synthetic data of mixed types using a GAN.
5
+ Author-email: "DataCebo, Inc." <info@sdv.dev>
6
+ License: BSL-1.1
7
+ Project-URL: Source Code, https://github.com/sdv-dev/Deepecho/
8
+ Project-URL: Issue Tracker, https://github.com/sdv-dev/Deepecho/issues
9
+ Project-URL: Twitter, https://twitter.com/sdv_dev
10
+ Project-URL: Chat, https://bit.ly/sdv-slack-invite
11
+ Keywords: deepecho,DeepEcho
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: Free for non-commercial use
15
+ Classifier: Natural Language :: English
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Requires-Python: <3.13,>=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: numpy>=1.20.0; python_version < "3.10"
27
+ Requires-Dist: numpy>=1.23.3; python_version >= "3.10" and python_version < "3.12"
28
+ Requires-Dist: numpy>=1.26.0; python_version >= "3.12"
29
+ Requires-Dist: pandas>=1.1.3; python_version < "3.10"
30
+ Requires-Dist: pandas>=1.3.4; python_version >= "3.10" and python_version < "3.11"
31
+ Requires-Dist: pandas>=1.5.0; python_version >= "3.11"
32
+ Requires-Dist: torch>=1.8.0; python_version < "3.10"
33
+ Requires-Dist: torch>=1.11.0; python_version >= "3.10" and python_version < "3.11"
34
+ Requires-Dist: torch>=2.0.0; python_version >= "3.11" and python_version < "3.12"
35
+ Requires-Dist: torch>=2.2.0; python_version >= "3.12"
36
+ Requires-Dist: tqdm>=4.29
37
+ Provides-Extra: test
38
+ Requires-Dist: pytest>=3.4.2; extra == "test"
39
+ Requires-Dist: pytest-cov>=2.6.0; extra == "test"
40
+ Requires-Dist: pytest-rerunfailures<15,>=10.3; extra == "test"
41
+ Requires-Dist: jupyter<2,>=1.0.0; extra == "test"
42
+ Requires-Dist: rundoc<0.5,>=0.4.3; extra == "test"
43
+ Requires-Dist: pytest-runner>=2.11.1; extra == "test"
44
+ Requires-Dist: tomli<3,>=2.0.0; extra == "test"
45
+ Provides-Extra: dev
46
+ Requires-Dist: deepecho[test]; extra == "dev"
47
+ Requires-Dist: setuptools<70; extra == "dev"
48
+ Requires-Dist: build<2,>=1.0.0; extra == "dev"
49
+ Requires-Dist: bump-my-version<1,>=0.18.3; extra == "dev"
50
+ Requires-Dist: pip>=9.0.1; extra == "dev"
51
+ Requires-Dist: watchdog<5,>=1.0.1; extra == "dev"
52
+ Requires-Dist: ruff<1,>=0.3.2; extra == "dev"
53
+ Requires-Dist: twine<4,>=1.10.0; extra == "dev"
54
+ Requires-Dist: wheel>=0.30.0; extra == "dev"
55
+ Requires-Dist: coverage<6,>=4.5.1; extra == "dev"
56
+ Requires-Dist: tox<4,>=2.9.1; extra == "dev"
57
+ Requires-Dist: invoke; extra == "dev"
58
+
59
+ <div align="center">
60
+ <br/>
61
+ <p align="center">
62
+ <i>This repository is part of <a href="https://sdv.dev">The Synthetic Data Vault Project</a>, a project from <a href="https://datacebo.com">DataCebo</a>.</i>
63
+ </p>
64
+
65
+ [![Development Status](https://img.shields.io/badge/Development%20Status-2%20--%20Pre--Alpha-yellow)](https://pypi.org/search/?c=Development+Status+%3A%3A+2+-+Pre-Alpha)
66
+ [![PyPi Shield](https://img.shields.io/pypi/v/deepecho.svg)](https://pypi.python.org/pypi/deepecho)
67
+ [![Tests](https://github.com/sdv-dev/DeepEcho/workflows/Run%20Tests/badge.svg)](https://github.com/sdv-dev/DeepEcho/actions?query=workflow%3A%22Run+Tests%22+branch%3Amain)
68
+ [![Downloads](https://pepy.tech/badge/deepecho)](https://pepy.tech/project/deepecho)
69
+ [![Coverage Status](https://codecov.io/gh/sdv-dev/DeepEcho/branch/main/graph/badge.svg)](https://codecov.io/gh/sdv-dev/DeepEcho)
70
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/sdv-dev/DeepEcho/main?filepath=tutorials/timeseries_data)
71
+ [![Slack](https://img.shields.io/badge/Slack%20Workspace-Join%20now!-36C5F0?logo=slack)](https://bit.ly/sdv-slack-invite)
72
+
73
+ <div align="left">
74
+ <br/>
75
+ <p align="center">
76
+ <a href="https://github.com/sdv-dev/DeepEcho">
77
+ <img align="center" width=40% src="https://github.com/sdv-dev/SDV/blob/stable/docs/images/DeepEcho-DataCebo.png"></img>
78
+ </a>
79
+ </p>
80
+ </div>
81
+
82
+ </div>
83
+
84
+ # Overview
85
+
86
+ **DeepEcho** is a **Synthetic Data Generation** Python library for **mixed-type**, **multivariate
87
+ time series**. It provides:
88
+
89
+ 1. Multiple models based both on **classical statistical modeling** of time series and the latest
90
+ in **Deep Learning** techniques.
91
+ 2. A robust [benchmarking framework](https://github.com/sdv-dev/SDGym) for evaluating these methods
92
+ on multiple datasets and with multiple metrics.
93
+ 3. Ability for **Machine Learning researchers** to submit new methods following our `model` and
94
+ `sample` API and get evaluated.
95
+
96
+ | Important Links | |
97
+ | --------------------------------------------- | -------------------------------------------------------------------- |
98
+ | :computer: **[Website]** | Check out the SDV Website for more information about the project. |
99
+ | :orange_book: **[SDV Blog]** | Regular publshing of useful content about Synthetic Data Generation. |
100
+ | :book: **[Documentation]** | Quickstarts, User and Development Guides, and API Reference. |
101
+ | :octocat: **[Repository]** | The link to the Github Repository of this library. |
102
+ | :keyboard: **[Development Status]** | This software is in its Pre-Alpha stage. |
103
+ | [![][Slack Logo] **Community**][Community] | Join our Slack Workspace for announcements and discussions. |
104
+ | [![][MyBinder Logo] **Tutorials**][Tutorials] | Run the SDV Tutorials in a Binder environment. |
105
+
106
+ [Website]: https://sdv.dev
107
+ [SDV Blog]: https://sdv.dev/blog
108
+ [Documentation]: https://sdv.dev/SDV
109
+ [Repository]: https://github.com/sdv-dev/DeepEcho
110
+ [License]: https://github.com/sdv-dev/DeepEcho/blob/main/LICENSE
111
+ [Development Status]: https://pypi.org/search/?c=Development+Status+%3A%3A+2+-+Pre-Alpha
112
+ [Slack Logo]: https://github.com/sdv-dev/SDV/blob/stable/docs/images/slack.png
113
+ [Community]: https://bit.ly/sdv-slack-invite
114
+ [MyBinder Logo]: https://github.com/sdv-dev/SDV/blob/stable/docs/images/mybinder.png
115
+ [Tutorials]: https://mybinder.org/v2/gh/sdv-dev/DeepEcho/main?filepath=tutorials
116
+
117
+ # Install
118
+
119
+ **DeepEcho** is part of the **SDV** project and is automatically installed alongside it. For
120
+ details about this process please visit the [SDV Installation Guide](
121
+ https://sdv.dev/SDV/getting_started/install.html)
122
+
123
+ Optionally, **DeepEcho** can also be installed as a standalone library using the following commands:
124
+
125
+ **Using `pip`:**
126
+
127
+ ```bash
128
+ pip install deepecho
129
+ ```
130
+
131
+ **Using `conda`:**
132
+
133
+ ```bash
134
+ conda install -c pytorch -c conda-forge deepecho
135
+ ```
136
+
137
+ For more installation options please visit the [DeepEcho installation Guide](INSTALL.md)
138
+
139
+ # Quickstart
140
+
141
+ **DeepEcho** is included as part of [SDV](https://sdv.dev/SDV) to model and sample synthetic
142
+ time series. In most cases, usage through SDV is recommeded, since it provides additional
143
+ functionalities which are not available here. For more details about how to use DeepEcho
144
+ whithin SDV, please visit the corresponding User Guide:
145
+
146
+ * [SDV TimeSeries User Guide](https://sdv.dev/SDV/user_guides/timeseries/par.html)
147
+
148
+ ## Standalone usage
149
+
150
+ **DeepEcho** can also be used as a standalone library.
151
+
152
+ In this short quickstart, we show how to learn a mixed-type multivariate time series
153
+ dataset and then generate synthetic data that resembles it.
154
+
155
+ We will start by loading the data and preparing the instance of our model.
156
+
157
+ ```python3
158
+ from deepecho import PARModel
159
+ from deepecho.demo import load_demo
160
+
161
+ # Load demo data
162
+ data = load_demo()
163
+
164
+ # Define data types for all the columns
165
+ data_types = {
166
+ 'region': 'categorical',
167
+ 'day_of_week': 'categorical',
168
+ 'total_sales': 'continuous',
169
+ 'nb_customers': 'count',
170
+ }
171
+
172
+ model = PARModel(cuda=False)
173
+ ```
174
+
175
+ If we want to use different settings for our model, like increasing the number
176
+ of epochs or enabling CUDA, we can pass the arguments when creating the model:
177
+
178
+ ```python # keep this as python (without the 3) to avoid using it in test-readme
179
+ model = PARModel(epochs=1024, cuda=True)
180
+ ```
181
+
182
+ Notice that for smaller datasets like the one used on this demo, CUDA usage introduces
183
+ more overhead than the gains it obtains from parallelization, so the process in this
184
+ case is more efficient without CUDA, even if it is available.
185
+
186
+ Once we have created our instance, we are ready to learn the data and generate
187
+ new synthetic data that resembles it:
188
+
189
+ ```python3
190
+ # Learn a model from the data
191
+ model.fit(
192
+ data=data,
193
+ entity_columns=['store_id'],
194
+ context_columns=['region'],
195
+ data_types=data_types,
196
+ sequence_index='date'
197
+ )
198
+
199
+ # Sample new data
200
+ model.sample(num_entities=5)
201
+ ```
202
+
203
+ The output will be a table with synthetic time series data with the same properties to
204
+ the demo data that we used as input.
205
+
206
+ # What's next?
207
+
208
+ For more details about **DeepEcho** and all its possibilities and features, please check and
209
+ run the [tutorials](tutorials).
210
+
211
+ If you want to see how we evaluate the performance and quality of our models, please have a
212
+ look at the [SDGym Benchmarking framework](https://github.com/sdv-dev/SDGym).
213
+
214
+ Also, please feel welcome to visit [our contributing guide](CONTRIBUTING.rst) in order to help
215
+ us developing new features or cool ideas!
216
+
217
+ ---
218
+
219
+
220
+ <div align="center">
221
+ <a href="https://datacebo.com"><img align="center" width=40% src="https://github.com/sdv-dev/SDV/blob/stable/docs/images/DataCebo.png"></img></a>
222
+ </div>
223
+ <br/>
224
+ <br/>
225
+
226
+ [The Synthetic Data Vault Project](https://sdv.dev) was first created at MIT's [Data to AI Lab](
227
+ https://dai.lids.mit.edu/) in 2016. After 4 years of research and traction with enterprise, we
228
+ created [DataCebo](https://datacebo.com) in 2020 with the goal of growing the project.
229
+ Today, DataCebo is the proud developer of SDV, the largest ecosystem for
230
+ synthetic data generation & evaluation. It is home to multiple libraries that support synthetic
231
+ data, including:
232
+
233
+ * 🔄 Data discovery & transformation. Reverse the transforms to reproduce realistic data.
234
+ * 🧠 Multiple machine learning models -- ranging from Copulas to Deep Learning -- to create tabular,
235
+ multi table and time series data.
236
+ * 📊 Measuring quality and privacy of synthetic data, and comparing different synthetic data
237
+ generation models.
238
+
239
+ [Get started using the SDV package](https://sdv.dev/SDV/getting_started/install.html) -- a fully
240
+ integrated solution and your one-stop shop for synthetic data. Or, use the standalone libraries
241
+ for specific needs.
@@ -2,7 +2,7 @@
2
2
 
3
3
  __author__ = 'DataCebo, Inc.'
4
4
  __email__ = 'info@sdv.dev'
5
- __version__ = '0.5.0.dev0'
5
+ __version__ = '0.6.0.dev0'
6
6
  __path__ = __import__('pkgutil').extend_path(__path__, __name__)
7
7
 
8
8
  from deepecho.demo import load_demo
@@ -6,7 +6,7 @@ import tqdm
6
6
  from deepecho.sequences import assemble_sequences
7
7
 
8
8
 
9
- class DeepEcho():
9
+ class DeepEcho:
10
10
  """The base class for DeepEcho models."""
11
11
 
12
12
  _verbose = True
@@ -28,7 +28,13 @@ class DeepEcho():
28
28
  data_types:
29
29
  See `fit`.
30
30
  """
31
- dtypes = set(['continuous', 'categorical', 'ordinal', 'count', 'datetime'])
31
+ dtypes = set([
32
+ 'continuous',
33
+ 'categorical',
34
+ 'ordinal',
35
+ 'count',
36
+ 'datetime',
37
+ ])
32
38
  assert all(dtype in dtypes for dtype in context_types)
33
39
  assert all(dtype in dtypes for dtype in data_types)
34
40
 
@@ -99,8 +105,15 @@ class DeepEcho():
99
105
 
100
106
  return dtypes_list
101
107
 
102
- def fit(self, data, entity_columns=None, context_columns=None,
103
- data_types=None, segment_size=None, sequence_index=None):
108
+ def fit(
109
+ self,
110
+ data,
111
+ entity_columns=None,
112
+ context_columns=None,
113
+ data_types=None,
114
+ segment_size=None,
115
+ sequence_index=None,
116
+ ):
104
117
  """Fit the model to a dataframe containing time series data.
105
118
 
106
119
  Args:
@@ -135,8 +148,7 @@ class DeepEcho():
135
148
  if segment_size is not None and not isinstance(segment_size, int):
136
149
  if sequence_index is None:
137
150
  raise TypeError(
138
- '`segment_size` must be of type `int` if '
139
- 'no `sequence_index` is given.'
151
+ '`segment_size` must be of type `int` if ' 'no `sequence_index` is given.'
140
152
  )
141
153
  if data[sequence_index].dtype.kind != 'M':
142
154
  raise TypeError(
@@ -161,7 +173,12 @@ class DeepEcho():
161
173
  data_types = self._get_data_types(data, data_types, self._data_columns)
162
174
  context_types = self._get_data_types(data, data_types, self._context_columns)
163
175
  sequences = assemble_sequences(
164
- data, self._entity_columns, self._context_columns, segment_size, sequence_index)
176
+ data,
177
+ self._entity_columns,
178
+ self._context_columns,
179
+ segment_size,
180
+ sequence_index,
181
+ )
165
182
 
166
183
  # Validate and fit
167
184
  self._validate(sequences, context_types, data_types)
@@ -242,7 +259,7 @@ class DeepEcho():
242
259
  # Reformat as a DataFrame
243
260
  group = pd.DataFrame(
244
261
  dict(zip(self._data_columns, sequence)),
245
- columns=self._data_columns
262
+ columns=self._data_columns,
246
263
  )
247
264
  group[self._entity_columns] = entity_values
248
265
  for column, value in zip(self._context_columns, context_values):
@@ -13,10 +13,13 @@ LOGGER = logging.getLogger(__name__)
13
13
 
14
14
 
15
15
  def _expand_context(data, context):
16
- return torch.cat([
17
- data,
18
- context.unsqueeze(0).expand(data.shape[0], context.shape[0], context.shape[1])
19
- ], dim=2)
16
+ return torch.cat(
17
+ [
18
+ data,
19
+ context.unsqueeze(0).expand(data.shape[0], context.shape[0], context.shape[1]),
20
+ ],
21
+ dim=2,
22
+ )
20
23
 
21
24
 
22
25
  class BasicGenerator(torch.nn.Module):
@@ -65,7 +68,7 @@ class BasicGenerator(torch.nn.Module):
65
68
  """
66
69
  latent = torch.randn(
67
70
  size=(sequence_length, context.size(0), self.latent_size),
68
- device=self.device
71
+ device=self.device,
69
72
  )
70
73
  latent = _expand_context(latent, context)
71
74
 
@@ -150,8 +153,16 @@ class BasicGANModel(DeepEcho):
150
153
  _model_data_size = None
151
154
  _generator = None
152
155
 
153
- def __init__(self, epochs=1024, latent_size=32, hidden_size=16,
154
- gen_lr=1e-3, dis_lr=1e-3, cuda=True, verbose=True):
156
+ def __init__(
157
+ self,
158
+ epochs=1024,
159
+ latent_size=32,
160
+ hidden_size=16,
161
+ gen_lr=1e-3,
162
+ dis_lr=1e-3,
163
+ cuda=True,
164
+ verbose=True,
165
+ ):
155
166
  self._epochs = epochs
156
167
  self._gen_lr = gen_lr
157
168
  self._dis_lr = dis_lr
@@ -211,7 +222,7 @@ class BasicGANModel(DeepEcho):
211
222
  'type': column_type,
212
223
  'min': np.min(values),
213
224
  'max': np.max(values),
214
- 'indices': (dimensions, dimensions + 1)
225
+ 'indices': (dimensions, dimensions + 1),
215
226
  }
216
227
  dimensions += 2
217
228
 
@@ -221,10 +232,7 @@ class BasicGANModel(DeepEcho):
221
232
  indices[value] = dimensions
222
233
  dimensions += 1
223
234
 
224
- mapping[column] = {
225
- 'type': column_type,
226
- 'indices': indices
227
- }
235
+ mapping[column] = {'type': column_type, 'indices': indices}
228
236
 
229
237
  else:
230
238
  raise ValueError(f'Unsupported type: {column_type}')
@@ -317,7 +325,7 @@ class BasicGANModel(DeepEcho):
317
325
  self._one_hot_encode(tensor, value, properties)
318
326
 
319
327
  else:
320
- raise ValueError() # Theoretically unreachable
328
+ raise ValueError() # Theoretically unreachable
321
329
 
322
330
  def _data_to_tensor(self, data):
323
331
  """Convert the input data to the corresponding tensor.
@@ -370,7 +378,7 @@ class BasicGANModel(DeepEcho):
370
378
  elif column_type in ('categorical', 'ordinal'):
371
379
  value = self._one_hot_decode(tensor, row, properties)
372
380
  else:
373
- raise ValueError() # Theoretically unreachable
381
+ raise ValueError() # Theoretically unreachable
374
382
 
375
383
  column_data.append(value)
376
384
 
@@ -412,7 +420,7 @@ class BasicGANModel(DeepEcho):
412
420
  end_flag = sequence[:, self._data_size]
413
421
  if (end_flag == 1.0).any():
414
422
  cut_idx = end_flag.detach().cpu().numpy().argmax()
415
- sequence[cut_idx + 1:] = 0.0
423
+ sequence[cut_idx + 1 :] = 0.0
416
424
 
417
425
  def _generate(self, context, sequence_length=None):
418
426
  generated = self._generator(
@@ -27,10 +27,13 @@ class PARNet(torch.nn.Module):
27
27
  if isinstance(x, torch.nn.utils.rnn.PackedSequence):
28
28
  x, lengths = torch.nn.utils.rnn.pad_packed_sequence(x)
29
29
  if self.context_size:
30
- x = torch.cat([
31
- x,
32
- c.unsqueeze(0).expand(x.shape[0], c.shape[0], c.shape[1])
33
- ], dim=2)
30
+ x = torch.cat(
31
+ [
32
+ x,
33
+ c.unsqueeze(0).expand(x.shape[0], c.shape[0], c.shape[1]),
34
+ ],
35
+ dim=2,
36
+ )
34
37
 
35
38
  x = self.down(x)
36
39
  x = torch.nn.utils.rnn.pack_padded_sequence(x, lengths, enforce_sorted=False)
@@ -41,10 +44,13 @@ class PARNet(torch.nn.Module):
41
44
 
42
45
  else:
43
46
  if self.context_size:
44
- x = torch.cat([
45
- x,
46
- c.unsqueeze(0).expand(x.shape[0], c.shape[0], c.shape[1])
47
- ], dim=2)
47
+ x = torch.cat(
48
+ [
49
+ x,
50
+ c.unsqueeze(0).expand(x.shape[0], c.shape[0], c.shape[1]),
51
+ ],
52
+ dim=2,
53
+ )
48
54
 
49
55
  x = self.down(x)
50
56
  x, _ = self.rnn(x)
@@ -126,7 +132,7 @@ class PARModel(DeepEcho):
126
132
  'mu': np.nanmean(x[i]),
127
133
  'std': np.nanstd(x[i]),
128
134
  'nulls': pd.isnull(x[i]).any(),
129
- 'indices': (idx, idx + 1, idx + 2)
135
+ 'indices': (idx, idx + 1, idx + 2),
130
136
  }
131
137
  idx += 3
132
138
 
@@ -136,15 +142,12 @@ class PARModel(DeepEcho):
136
142
  'min': np.nanmin(x[i]),
137
143
  'range': np.nanmax(x[i]) - np.nanmin(x[i]),
138
144
  'nulls': pd.isnull(x[i]).any(),
139
- 'indices': (idx, idx + 1, idx + 2)
145
+ 'indices': (idx, idx + 1, idx + 2),
140
146
  }
141
147
  idx += 3
142
148
 
143
149
  elif t == 'categorical' or t == 'ordinal':
144
- idx_map[i] = {
145
- 'type': t,
146
- 'indices': {}
147
- }
150
+ idx_map[i] = {'type': t, 'indices': {}}
148
151
  idx += 1
149
152
  for v in set(x[i]):
150
153
  if pd.isnull(v):
@@ -186,8 +189,8 @@ class PARModel(DeepEcho):
186
189
  'indices': {
187
190
  '<START>': self._data_dims,
188
191
  '<END>': self._data_dims + 1,
189
- '<BODY>': self._data_dims + 2
190
- }
192
+ '<BODY>': self._data_dims + 2,
193
+ },
191
194
  }
192
195
  self._data_dims += 3
193
196
 
@@ -225,7 +228,10 @@ class PARModel(DeepEcho):
225
228
  x[p_idx] = 0.0
226
229
  x[missing_idx] = 1.0 if pd.isnull(data[key][i]) else 0.0
227
230
 
228
- elif props['type'] in ['categorical', 'ordinal']: # categorical
231
+ elif props['type'] in [
232
+ 'categorical',
233
+ 'ordinal',
234
+ ]: # categorical
229
235
  value = data[key][i]
230
236
  if pd.isnull(value):
231
237
  value = None
@@ -250,15 +256,21 @@ class PARModel(DeepEcho):
250
256
  for key, props in self._ctx_map.items():
251
257
  if props['type'] in ['continuous', 'datetime']:
252
258
  mu_idx, sigma_idx, missing_idx = props['indices']
253
- x[mu_idx] = 0.0 if (pd.isnull(context[key]) or props['std'] == 0) else (
254
- context[key] - props['mu']) / props['std']
259
+ x[mu_idx] = (
260
+ 0.0
261
+ if (pd.isnull(context[key]) or props['std'] == 0)
262
+ else (context[key] - props['mu']) / props['std']
263
+ )
255
264
  x[sigma_idx] = 0.0
256
265
  x[missing_idx] = 1.0 if pd.isnull(context[key]) else 0.0
257
266
 
258
267
  elif props['type'] in ['count']:
259
268
  r_idx, p_idx, missing_idx = props['indices']
260
- x[r_idx] = 0.0 if (pd.isnull(context[key]) or props['range'] == 0) else (
261
- context[key] - props['min']) / props['range']
269
+ x[r_idx] = (
270
+ 0.0
271
+ if (pd.isnull(context[key]) or props['range'] == 0)
272
+ else (context[key] - props['min']) / props['range']
273
+ )
262
274
  x[p_idx] = 0.0
263
275
  x[missing_idx] = 1.0 if pd.isnull(context[key]) else 0.0
264
276
 
@@ -341,12 +353,13 @@ class PARModel(DeepEcho):
341
353
 
342
354
  epoch_loss_df = pd.DataFrame({
343
355
  'Epoch': [epoch],
344
- 'Loss': [loss.item()]
356
+ 'Loss': [loss.item()],
345
357
  })
346
358
  if not self.loss_values.empty:
347
- self.loss_values = pd.concat(
348
- [self.loss_values, epoch_loss_df]
349
- ).reset_index(drop=True)
359
+ self.loss_values = pd.concat([
360
+ self.loss_values,
361
+ epoch_loss_df,
362
+ ]).reset_index(drop=True)
350
363
  else:
351
364
  self.loss_values = epoch_loss_df
352
365
 
@@ -375,7 +388,7 @@ class PARModel(DeepEcho):
375
388
  This list contains the length of each sequence.
376
389
  """
377
390
  log_likelihood = 0.0
378
- _, batch_size, input_size = X_padded.shape
391
+ _, batch_size, _input_size = X_padded.shape
379
392
 
380
393
  for key, props in self._data_map.items():
381
394
  if props['type'] in ['continuous', 'timestamp']:
@@ -386,14 +399,16 @@ class PARModel(DeepEcho):
386
399
 
387
400
  for i in range(batch_size):
388
401
  dist = torch.distributions.normal.Normal(
389
- mu[:seq_len[i], i], sigma[:seq_len[i], i])
390
- log_likelihood += torch.sum(dist.log_prob(X_padded[-seq_len[i]:, i, mu_idx]))
402
+ mu[: seq_len[i], i], sigma[: seq_len[i], i]
403
+ )
404
+ log_likelihood += torch.sum(dist.log_prob(X_padded[-seq_len[i] :, i, mu_idx]))
391
405
 
392
- p_true = X_padded[:seq_len[i], i, missing_idx]
393
- p_pred = missing[:seq_len[i], i]
406
+ p_true = X_padded[: seq_len[i], i, missing_idx]
407
+ p_pred = missing[: seq_len[i], i]
394
408
  log_likelihood += torch.sum(p_true * p_pred)
395
- log_likelihood += torch.sum((1.0 - p_true) * torch.log(
396
- 1.0 - torch.exp(p_pred)))
409
+ log_likelihood += torch.sum(
410
+ (1.0 - p_true) * torch.log(1.0 - torch.exp(p_pred))
411
+ )
397
412
 
398
413
  elif props['type'] in ['count']:
399
414
  r_idx, p_idx, missing_idx = props['indices']
@@ -404,22 +419,26 @@ class PARModel(DeepEcho):
404
419
 
405
420
  for i in range(batch_size):
406
421
  dist = torch.distributions.negative_binomial.NegativeBinomial(
407
- r[:seq_len[i], i], p[:seq_len[i], i], validate_args=False)
408
- log_likelihood += torch.sum(dist.log_prob(x[:seq_len[i], i]))
409
-
410
- p_true = X_padded[:seq_len[i], i, missing_idx]
411
- p_pred = missing[:seq_len[i], i]
422
+ r[: seq_len[i], i],
423
+ p[: seq_len[i], i],
424
+ validate_args=False,
425
+ )
426
+ log_likelihood += torch.sum(dist.log_prob(x[: seq_len[i], i]))
427
+
428
+ p_true = X_padded[: seq_len[i], i, missing_idx]
429
+ p_pred = missing[: seq_len[i], i]
412
430
  log_likelihood += torch.sum(p_true * p_pred)
413
- log_likelihood += torch.sum((1.0 - p_true) * torch.log(
414
- 1.0 - torch.exp(p_pred)))
431
+ log_likelihood += torch.sum(
432
+ (1.0 - p_true) * torch.log(1.0 - torch.exp(p_pred))
433
+ )
415
434
 
416
435
  elif props['type'] in ['categorical', 'ordinal']:
417
436
  idx = list(props['indices'].values())
418
437
  log_softmax = torch.nn.functional.log_softmax(Y_padded[:, :, idx], dim=2)
419
438
 
420
439
  for i in range(batch_size):
421
- target = X_padded[:seq_len[i], i, idx]
422
- predicted = log_softmax[:seq_len[i], i]
440
+ target = X_padded[: seq_len[i], i, idx]
441
+ predicted = log_softmax[: seq_len[i], i]
423
442
  target = torch.argmax(target, dim=1).unsqueeze(dim=1)
424
443
  log_likelihood += torch.sum(predicted.gather(dim=1, index=target))
425
444
 
@@ -443,14 +462,14 @@ class PARModel(DeepEcho):
443
462
  data[key] = []
444
463
  for i in range(seq_len):
445
464
  if props['type'] in ['continuous', 'datetime']:
446
- mu_idx, sigma_idx, missing_idx = props['indices']
465
+ mu_idx, _sigma_idx, missing_idx = props['indices']
447
466
  if (x[i, 0, missing_idx] > 0) and props['nulls']:
448
467
  data[key].append(None)
449
468
  else:
450
469
  data[key].append(x[i, 0, mu_idx].item() * props['std'] + props['mu'])
451
470
 
452
471
  elif props['type'] in ['count']:
453
- r_idx, p_idx, missing_idx = props['indices']
472
+ r_idx, _p_idx, missing_idx = props['indices']
454
473
  if x[i, 0, missing_idx] > 0 and props['nulls']:
455
474
  data[key].append(None)
456
475
  else:
@@ -473,7 +492,7 @@ class PARModel(DeepEcho):
473
492
 
474
493
  def _sample_state(self, x):
475
494
  log_likelihood = 0.0
476
- seq_len, batch_size, input_size = x.shape
495
+ seq_len, batch_size, _input_size = x.shape
477
496
  assert seq_len == 1 and batch_size == 1
478
497
 
479
498
  for key, props in self._data_map.items():