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.
- deepecho-0.6.0.dev0/PKG-INFO +241 -0
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/__init__.py +1 -1
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/models/base.py +25 -8
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/models/basic_gan.py +23 -15
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/models/par.py +63 -44
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/sequences.py +13 -12
- deepecho-0.6.0.dev0/deepecho.egg-info/PKG-INFO +241 -0
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho.egg-info/SOURCES.txt +2 -13
- deepecho-0.6.0.dev0/deepecho.egg-info/requires.txt +46 -0
- deepecho-0.6.0.dev0/pyproject.toml +205 -0
- deepecho-0.6.0.dev0/setup.cfg +4 -0
- deepecho-0.6.0.dev0/tests/test_tasks.py +39 -0
- deepecho-0.5.0.dev0/AUTHORS.rst +0 -1
- deepecho-0.5.0.dev0/CONTRIBUTING.rst +0 -237
- deepecho-0.5.0.dev0/HISTORY.md +0 -92
- deepecho-0.5.0.dev0/MANIFEST.in +0 -12
- deepecho-0.5.0.dev0/PKG-INFO +0 -302
- deepecho-0.5.0.dev0/deepecho.egg-info/PKG-INFO +0 -302
- deepecho-0.5.0.dev0/deepecho.egg-info/not-zip-safe +0 -1
- deepecho-0.5.0.dev0/deepecho.egg-info/requires.txt +0 -61
- deepecho-0.5.0.dev0/setup.cfg +0 -76
- deepecho-0.5.0.dev0/setup.py +0 -117
- deepecho-0.5.0.dev0/tests/__init__.py +0 -1
- deepecho-0.5.0.dev0/tests/integration/__init__.py +0 -1
- deepecho-0.5.0.dev0/tests/integration/test_basic_gan.py +0 -134
- deepecho-0.5.0.dev0/tests/integration/test_par.py +0 -156
- deepecho-0.5.0.dev0/tests/unit/__init__.py +0 -1
- deepecho-0.5.0.dev0/tests/unit/test_sequences.py +0 -255
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/LICENSE +0 -0
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/README.md +0 -0
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/data/demo.csv +0 -0
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/demo.py +0 -0
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho/models/__init__.py +0 -0
- {deepecho-0.5.0.dev0 → deepecho-0.6.0.dev0}/deepecho.egg-info/dependency_links.txt +0 -0
- {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
|
+
[](https://pypi.org/search/?c=Development+Status+%3A%3A+2+-+Pre-Alpha)
|
|
66
|
+
[](https://pypi.python.org/pypi/deepecho)
|
|
67
|
+
[](https://github.com/sdv-dev/DeepEcho/actions?query=workflow%3A%22Run+Tests%22+branch%3Amain)
|
|
68
|
+
[](https://pepy.tech/project/deepecho)
|
|
69
|
+
[](https://codecov.io/gh/sdv-dev/DeepEcho)
|
|
70
|
+
[](https://mybinder.org/v2/gh/sdv-dev/DeepEcho/main?filepath=tutorials/timeseries_data)
|
|
71
|
+
[](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.
|
|
@@ -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([
|
|
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(
|
|
103
|
-
|
|
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,
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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__(
|
|
154
|
-
|
|
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()
|
|
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()
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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 [
|
|
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] =
|
|
254
|
-
|
|
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] =
|
|
261
|
-
|
|
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
|
-
|
|
349
|
-
|
|
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,
|
|
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
|
-
|
|
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(
|
|
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[:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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(
|
|
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,
|
|
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,
|
|
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,
|
|
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():
|