diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..02c381e --- /dev/null +++ b/.gitignore @@ -0,0 +1,145 @@ +### Data ### +data/ +erc/ + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# End of https://www.toptal.com/developers/gitignore/api/python \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..89ecc5a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Time Series Generation \ No newline at end of file diff --git a/Timeseries_clustering.ipynb b/Timeseries_clustering.ipynb new file mode 100644 index 0000000..7f59b46 --- /dev/null +++ b/Timeseries_clustering.ipynb @@ -0,0 +1,1635 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Timeseries clustering\n", + "\n", + "Time series clustering is to partition time series data into groups based on similarity or distance, so that time series in the same cluster are similar.\n", + "\n", + "Methodology followed:\n", + "* Use Variational Recurrent AutoEncoder (VRAE) for dimensionality reduction of the timeseries\n", + "* To visualize the clusters, PCA and t-sne are used\n", + "\n", + "Paper:\n", + "https://arxiv.org/pdf/1412.6581.pdf" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Contents\n", + "\n", + "0. [Load data and preprocess](#Load-data-and-preprocess)\n", + "1. [Initialize VRAE object](#Initialize-VRAE-object)\n", + "2. [Fit the model onto dataset](#Fit-the-model-onto-dataset)\n", + "3. [Transform the input timeseries to encoded latent vectors](#Transform-the-input-timeseries-to-encoded-latent-vectors)\n", + "4. [Save the model to be fetched later](#Save-the-model-to-be-fetched-later)\n", + "5. [Visualize using PCA and tSNE](#Visualize-using-PCA-and-tSNE)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import required modules" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from model.org_vrae import VRAE\n", + "from model.utils import *\n", + "import numpy as np\n", + "import torch\n", + "\n", + "import plotly\n", + "from torch.utils.data import DataLoader, TensorDataset\n", + "plotly.offline.init_notebook_mode()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Input parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "dload = './model_dir' #download directory" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Hyper parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "hidden_size = 90\n", + "hidden_layer_depth = 1\n", + "latent_length = 20\n", + "batch_size = 32\n", + "learning_rate = 0.0005\n", + "n_epochs = 1\n", + "dropout_rate = 0.2\n", + "optimizer = 'Adam' # options: ADAM, SGD\n", + "cuda = True # options: True, False\n", + "print_every=30\n", + "clip = True # options: True, False\n", + "max_grad_norm=5\n", + "loss = 'MSELoss' # options: SmoothL1Loss, MSELoss\n", + "block = 'LSTM' # options: LSTM, GRU" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load data and preprocess" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "X_train, X_val, y_train, y_val = open_data('data', ratio_train=0.9)\n", + "\n", + "num_classes = len(np.unique(y_train))\n", + "base = np.min(y_train) # Check if data is 0-based\n", + "if base != 0:\n", + " y_train -= base\n", + "y_val -= base" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(8549, 140, 1)\n" + ] + } + ], + "source": [ + "print(X_train.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "train_dataset = TensorDataset(torch.from_numpy(X_train))\n", + "test_dataset = TensorDataset(torch.from_numpy(X_val))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Fetch `sequence_length` from dataset**" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "140" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sequence_length = X_train.shape[1]\n", + "sequence_length" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Fetch `number_of_features` from dataset**\n", + "\n", + "This config corresponds to number of input features" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "number_of_features = X_train.shape[2]\n", + "number_of_features" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Initialize VRAE object\n", + "\n", + "VRAE inherits from `sklearn.base.BaseEstimator` and overrides `fit`, `transform` and `fit_transform` functions, similar to sklearn modules" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.6/dist-packages/torch/nn/modules/rnn.py:65: UserWarning:\n", + "\n", + "dropout option adds dropout after all but last recurrent layer, so non-zero dropout expects num_layers greater than 1, but got dropout=0.2 and num_layers=1\n", + "\n", + "/usr/local/lib/python3.6/dist-packages/torch/nn/_reduction.py:42: UserWarning:\n", + "\n", + "size_average and reduce args will be deprecated, please use reduction='sum' instead.\n", + "\n" + ] + } + ], + "source": [ + "vrae = VRAE(sequence_length=sequence_length,\n", + " number_of_features = number_of_features,\n", + " hidden_size = hidden_size, \n", + " hidden_layer_depth = hidden_layer_depth,\n", + " latent_length = latent_length,\n", + " batch_size = batch_size,\n", + " learning_rate = learning_rate,\n", + " n_epochs = n_epochs,\n", + " dropout_rate = dropout_rate,\n", + " optimizer = optimizer, \n", + " cuda = cuda,\n", + " print_every=print_every, \n", + " clip=clip, \n", + " max_grad_norm=max_grad_norm,\n", + " loss = loss,\n", + " block = block,\n", + " dload = dload)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fit the model onto dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fit result\n", + "torch.Size([32, 140, 1])\n", + "Epoch: 0\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Batch 30, loss = 4126.4561, recon_loss = 4126.3960, kl_loss = 0.0602\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Batch 60, loss = 3002.3113, recon_loss = 2999.1250, kl_loss = 3.1863\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Batch 90, loss = 2697.9019, recon_loss = 2694.5222, kl_loss = 3.3796\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Batch 120, loss = 2783.7349, recon_loss = 2780.4021, kl_loss = 3.3327\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Batch 150, loss = 2799.6096, recon_loss = 2796.6382, kl_loss = 2.9714\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Batch 180, loss = 2885.5581, recon_loss = 2882.9241, kl_loss = 2.6341\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Batch 210, loss = 2366.8254, recon_loss = 2364.6108, kl_loss = 2.2146\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Batch 240, loss = 2797.3643, recon_loss = 2795.4651, kl_loss = 1.8991\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "Average loss: 2893.1905\n" + ] + } + ], + "source": [ + "vrae.fit(train_dataset)\n", + "\n", + "#If the model has to be saved, with the learnt parameters use:\n", + "# vrae.fit(dataset, save = True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Transform the input timeseries to encoded latent vectors" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([140, 32, 1])\n", + "--------------------------\n" + ] + } + ], + "source": [ + "z_run = vrae.transform(test_dataset)\n", + "\n", + "#If the latent vectors have to be saved, pass the parameter `save`\n", + "# z_run = vrae.transform(dataset, save = True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Save the model to be fetched later" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "vrae.save('vrae.pth')\n", + "\n", + "# To load a presaved model, execute:\n", + "# vrae.load('vrae.pth')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git "a/VRAE_\354\230\210\354\213\234.ipynb" "b/VRAE_\354\230\210\354\213\234.ipynb" new file mode 100644 index 0000000..c88052c --- /dev/null +++ "b/VRAE_\354\230\210\354\213\234.ipynb" @@ -0,0 +1,656 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Contents\n", + "\n", + "0. [Load data and preprocess](#Load-data-and-preprocess)\n", + "1. [Initialize VRAE object](#Initialize-VRAE-object)\n", + "2. [Fit the model onto dataset](#Fit-the-model-onto-dataset)\n", + "3. [Transform the input timeseries to encoded latent vectors](#Transform-the-input-timeseries-to-encoded-latent-vectors)\n", + "4. [Save the model to be fetched later](#Save-the-model-to-be-fetched-later)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import required modules" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "from model.vrae import VRAE\n", + "from model.utils import *\n", + "import numpy as np\n", + "import torch\n", + "from torch.utils.data import DataLoader, Dataset\n", + "from tqdm.notebook import trange\n", + "import tqdm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Input parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "dload = './saved_model' #download directory" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Hyper parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load data and preprocess\n", + "- `folder` : data location\n", + "- `cols_to_remove` : generation 수행하지 않을 column 제거" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**TODO : 해당 변수에 대한 처리를 어떻게 해줘야하는가 확인 작업이 필요함**\n", + "\n", + "~~~\n", + "YYYYMMDD : 년월일\n", + "HHMMSS : 시분초\n", + "MNG_NO : 장비번호\n", + "IF_IDX : 회선 index\n", + "~~~\n", + "\n", + "- 현재는 분석의 편의를 위해 ['YYYYMMDD', 'HHMMSS']만 제거해줌" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(23195128, 56)\n" + ] + } + ], + "source": [ + "# params\n", + "folder = 'data'\n", + "cols_to_remove = ['YYYYMMDD', 'HHMMSS']\n", + "\n", + "# load data\n", + "df_total = load_data(folder, cols_to_remove)\n", + "\n", + "# shape\n", + "print(df_total.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "class HamonDataset(Dataset):\n", + " def __init__(self, data, window, stride):\n", + " self.data = torch.Tensor(data)\n", + " self.window = window\n", + " \n", + " def __len__(self):\n", + " return len(self.data) - self.window \n", + " \n", + " def __getitem__(self, index):\n", + " x_index = index*self.window\n", + " x = self.data[x_index:x_index+self.window]\n", + " return x" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "data = df_total\n", + "stride = 10\n", + "window = 100" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.HamonDataset at 0x7f7cbaa3f940>" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_dataset = HamonDataset(data, window, stride)\n", + "train_dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([100, 56])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_dataset[0].shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Fetch `sequence_length` from dataset**" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "100" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sequence_length = train_dataset[0].shape[0]\n", + "sequence_length" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Fetch `number_of_features` from dataset**\n", + "\n", + "This config corresponds to number of input features" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "56" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "number_of_features = train_dataset[0].shape[1]\n", + "number_of_features" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "n_epochs = 1\n", + "hidden_size = 90\n", + "hidden_layer_depth = 1\n", + "latent_length = 20\n", + "batch_size = 32\n", + "learning_rate = 0.0005\n", + "dropout_rate = 0.2\n", + "optimizer = 'Adam' # options: ADAM, SGD\n", + "cuda = True # options: True, False\n", + "print_every=30\n", + "clip = True # options: True, False\n", + "max_grad_norm=5\n", + "loss = 'MSELoss' # options: SmoothL1Loss, MSELoss\n", + "block = 'LSTM' # options: LSTM, GRU" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "train_loader = DataLoader(dataset = train_dataset,\n", + " batch_size = batch_size,\n", + " shuffle = False,\n", + " drop_last=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[[2.7220e+03, 1.2400e+02, 1.8431e+05, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.7220e+03, 1.2400e+02, 3.8349e+05, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.7220e+03, 1.2400e+02, 2.3519e+05, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " ...,\n", + " [2.8500e+03, 1.2400e+02, 2.3200e+02, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00]],\n", + "\n", + " [[2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " ...,\n", + " [2.8630e+03, 1.2400e+02, 1.8664e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8630e+03, 1.2400e+02, 1.9056e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8630e+03, 1.2400e+02, 1.8104e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00]],\n", + "\n", + " [[2.8630e+03, 1.2400e+02, 1.8096e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8630e+03, 1.2400e+02, 1.8640e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8630e+03, 1.2400e+02, 1.9448e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " ...,\n", + " [2.8730e+03, 1.2400e+02, 3.3920e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8730e+03, 1.2400e+02, 3.4480e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [2.8730e+03, 1.2400e+02, 3.3840e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00]],\n", + "\n", + " ...,\n", + "\n", + " [[3.7730e+03, 1.2400e+02, 2.0880e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7730e+03, 1.2400e+02, 1.9360e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7730e+03, 1.2400e+02, 1.9840e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " ...,\n", + " [3.7810e+03, 1.2400e+02, 1.7760e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7810e+03, 1.2400e+02, 1.6800e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7810e+03, 1.2400e+02, 1.7600e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00]],\n", + "\n", + " [[3.7820e+03, 1.2400e+02, 5.1096e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7820e+03, 1.2400e+02, 1.2566e+06, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7820e+03, 1.2400e+02, 5.2016e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " ...,\n", + " [3.7900e+03, 1.2400e+02, 1.6496e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7900e+03, 1.2400e+02, 1.6416e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7900e+03, 1.2400e+02, 1.6776e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00]],\n", + "\n", + " [[3.7900e+03, 1.2400e+02, 1.6032e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7900e+03, 1.2400e+02, 1.6528e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7900e+03, 1.2400e+02, 1.7032e+04, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " ...,\n", + " [3.7980e+03, 1.2400e+02, 6.1760e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7980e+03, 1.2400e+02, 6.1920e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00],\n", + " [3.7980e+03, 1.2400e+02, 5.9840e+03, ..., 0.0000e+00,\n", + " 0.0000e+00, 0.0000e+00]]])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X = iter(train_loader).next()\n", + "X" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([32, 100, 56])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Initialize VRAE object\n", + "\n", + "VRAE inherits from `sklearn.base.BaseEstimator` and overrides `fit`, `transform` and `fit_transform` functions, similar to sklearn modules" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "vrae = VRAE(sequence_length=sequence_length,\n", + " number_of_features = number_of_features,\n", + " hidden_size = hidden_size, \n", + " hidden_layer_depth = hidden_layer_depth,\n", + " latent_length = latent_length,\n", + " batch_size = batch_size,\n", + " learning_rate = learning_rate,\n", + " n_epochs = n_epochs,\n", + " dropout_rate = dropout_rate,\n", + " optimizer = optimizer, \n", + " cuda = cuda,\n", + " print_every=print_every, \n", + " clip=clip, \n", + " max_grad_norm=max_grad_norm,\n", + " loss = loss,\n", + " block = block,\n", + " dload = dload)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fit the model onto dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[2.7220e+03, 1.2400e+02, 1.8431e+05, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " [2.7220e+03, 1.2400e+02, 3.8349e+05, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " [2.7220e+03, 1.2400e+02, 2.3519e+05, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " ...,\n", + " [2.8500e+03, 1.2400e+02, 2.3200e+02, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " [2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " [2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00]])" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_dataset[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "train_loader_test = DataLoader(dataset = train_dataset[0],\n", + " batch_size = 32,\n", + " shuffle = False,\n", + " drop_last=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([32, 56])\n" + ] + } + ], + "source": [ + "tmp = iter(train_loader_test).next()\n", + "print(tmp.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fit result\n", + "<__main__.HamonDataset object at 0x7f7cbaa3f940>\n", + "tensor([[2.7220e+03, 1.2400e+02, 1.8431e+05, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " [2.7220e+03, 1.2400e+02, 3.8349e+05, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " [2.7220e+03, 1.2400e+02, 2.3519e+05, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " ...,\n", + " [2.8500e+03, 1.2400e+02, 2.3200e+02, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " [2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00],\n", + " [2.8500e+03, 1.2400e+02, 2.4000e+02, ..., 0.0000e+00, 0.0000e+00,\n", + " 0.0000e+00]])\n", + "torch.Size([32, 100, 56])\n", + "Epoch: 0\n", + "--------------------------\n", + "DEBUGGING\n", + "torch.Size([32, 100, 56])\n", + "--------------------------\n" + ] + }, + { + "ename": "RuntimeError", + "evalue": "Expected hidden[0] size (1, 32, 90), got [1, 100, 90]", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mvrae\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtrain_dataset\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;31m#If the model has to be saved, with the learnt parameters use:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# vrae.fit(dataset, save = True)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/repo/projects/timeseries-generation/model/vrae.py\u001b[0m in \u001b[0;36mfit\u001b[0;34m(self, dataset, save)\u001b[0m\n\u001b[1;32m 352\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Epoch: %s'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 353\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 354\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_train\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtrain_loader\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 355\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 356\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_fitted\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/repo/projects/timeseries-generation/model/vrae.py\u001b[0m in \u001b[0;36m_train\u001b[0;34m(self, train_loader)\u001b[0m\n\u001b[1;32m 308\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 309\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moptimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzero_grad\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 310\u001b[0;31m \u001b[0mloss\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecon_loss\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkl_loss\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcompute_loss\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 311\u001b[0m \u001b[0mloss\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 312\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/repo/projects/timeseries-generation/model/vrae.py\u001b[0m in \u001b[0;36mcompute_loss\u001b[0;34m(self, X)\u001b[0m\n\u001b[1;32m 287\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mVariable\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrequires_grad\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 288\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 289\u001b[0;31m \u001b[0mx_decoded\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 290\u001b[0m \u001b[0mloss\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrecon_loss\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkl_loss\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_rec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx_decoded\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdetach\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloss_fn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 291\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 1100\u001b[0m if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks\n\u001b[1;32m 1101\u001b[0m or _global_forward_hooks or _global_forward_pre_hooks):\n\u001b[0;32m-> 1102\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mforward_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1103\u001b[0m \u001b[0;31m# Do not call functions when jit is used\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1104\u001b[0m \u001b[0mfull_backward_hooks\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnon_full_backward_hooks\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/repo/projects/timeseries-generation/model/vrae.py\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 257\u001b[0m \u001b[0mcell_output\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mencoder\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 258\u001b[0m \u001b[0mlatent\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlmbd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcell_output\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 259\u001b[0;31m \u001b[0mx_decoded\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoder\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlatent\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 260\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 261\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mx_decoded\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlatent\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 1100\u001b[0m if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks\n\u001b[1;32m 1101\u001b[0m or _global_forward_hooks or _global_forward_pre_hooks):\n\u001b[0;32m-> 1102\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mforward_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1103\u001b[0m \u001b[0;31m# Do not call functions when jit is used\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1104\u001b[0m \u001b[0mfull_backward_hooks\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnon_full_backward_hooks\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/repo/projects/timeseries-generation/model/vrae.py\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, latent)\u001b[0m\n\u001b[1;32m 139\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mLSTM\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 140\u001b[0m \u001b[0mh_0\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstack\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mh_state\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhidden_layer_depth\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 141\u001b[0;31m \u001b[0mdecoder_output\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecoder_inputs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mh_0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mc_0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 142\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mGRU\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 143\u001b[0m \u001b[0mh_0\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstack\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mh_state\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhidden_layer_depth\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_call_impl\u001b[0;34m(self, *input, **kwargs)\u001b[0m\n\u001b[1;32m 1100\u001b[0m if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks\n\u001b[1;32m 1101\u001b[0m or _global_forward_hooks or _global_forward_pre_hooks):\n\u001b[0;32m-> 1102\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mforward_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1103\u001b[0m \u001b[0;31m# Do not call functions when jit is used\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1104\u001b[0m \u001b[0mfull_backward_hooks\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnon_full_backward_hooks\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/torch/nn/modules/rnn.py\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, input, hx)\u001b[0m\n\u001b[1;32m 687\u001b[0m \u001b[0mhx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpermute_hidden\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msorted_indices\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 688\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 689\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheck_forward_args\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbatch_sizes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 690\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mbatch_sizes\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 691\u001b[0m result = _VF.lstm(input, hx, self._flat_weights, self.bias, self.num_layers,\n", + "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/torch/nn/modules/rnn.py\u001b[0m in \u001b[0;36mcheck_forward_args\u001b[0;34m(self, input, hidden, batch_sizes)\u001b[0m\n\u001b[1;32m 632\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheck_input\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbatch_sizes\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 633\u001b[0m self.check_hidden_size(hidden[0], self.get_expected_hidden_size(input, batch_sizes),\n\u001b[0;32m--> 634\u001b[0;31m 'Expected hidden[0] size {}, got {}')\n\u001b[0m\u001b[1;32m 635\u001b[0m self.check_hidden_size(hidden[1], self.get_expected_cell_size(input, batch_sizes),\n\u001b[1;32m 636\u001b[0m 'Expected hidden[1] size {}, got {}')\n", + "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/torch/nn/modules/rnn.py\u001b[0m in \u001b[0;36mcheck_hidden_size\u001b[0;34m(self, hx, expected_hidden_size, msg)\u001b[0m\n\u001b[1;32m 224\u001b[0m msg: str = 'Expected hidden size {}, got {}') -> None:\n\u001b[1;32m 225\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mhx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mexpected_hidden_size\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 226\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mexpected_hidden_size\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 227\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 228\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcheck_forward_args\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mTensor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mhidden\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mTensor\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbatch_sizes\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mOptional\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mTensor\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mRuntimeError\u001b[0m: Expected hidden[0] size (1, 32, 90), got [1, 100, 90]" + ] + } + ], + "source": [ + "vrae.fit(train_dataset)\n", + "\n", + "#If the model has to be saved, with the learnt parameters use:\n", + "# vrae.fit(dataset, save = True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Transform the input timeseries to encoded latent vectors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z_run = vrae.transform(test_dataset)\n", + "\n", + "#If the latent vectors have to be saved, pass the parameter `save`\n", + "# z_run = vrae.transform(dataset, save = True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Save the model to be fetched later" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vrae.save('vrae.pth')\n", + "\n", + "# To load a presaved model, execute:\n", + "# vrae.load('vrae.pth')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Visualize using PCA and tSNE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plot_clustering(z_run, y_val, engine='matplotlib', download = False)\n", + "\n", + "# If plotly to be used as rendering engine, uncomment below line\n", + "#plot_clustering(z_run, y_val, engine='plotly', download = False)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/etc/Hamon_Data_concat.ipynb b/etc/Hamon_Data_concat.ipynb new file mode 100644 index 0000000..9a5271b --- /dev/null +++ b/etc/Hamon_Data_concat.ipynb @@ -0,0 +1,1040 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 8, + "id": "08f72edc", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pandas as pd\n", + "import glob" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "89b19595", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/repo/projects/timeseries-generation/etc'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "os.getcwd()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b4f6150c", + "metadata": {}, + "outputs": [], + "source": [ + "# data_path = '/repo/projects/HAI_timeseries/Hamon_dataset/*.csv'\n", + "data_path = '../data/*.csv'" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "2e32eabf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['../data/20210620.csv',\n", + " '../data/20210621.csv',\n", + " '../data/20210622.csv',\n", + " '../data/20210623.csv',\n", + " '../data/20210624.csv',\n", + " '../data/20210625.csv',\n", + " '../data/20210626.csv']" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "file_list = glob.glob(data_path)\n", + "file_list.sort()\n", + "file_list" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "6ac1b77f", + "metadata": {}, + "outputs": [], + "source": [ + "# 전체 데이터\n", + "df_total = pd.DataFrame()\n", + "\n", + "for i in file_list:\n", + " data = pd.read_csv(i)\n", + " df_total = pd.concat([df_total, data])\n", + "\n", + "df_total = df_total.reset_index(drop = True)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "010299a0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YYYYMMDDHHMMSSMNG_NOIF_IDXAVG_INBPSMIN_INBPSMAX_INBPSAVG_OUTBPSMIN_OUTBPSMAX_OUTBPS...MAX_INMCASTPPSAVG_OUTMCASTPPSMIN_OUTMCASTPPSMAX_OUTMCASTPPSAVG_INBCASTPPSMIN_INBCASTPPSMAX_INBCASTPPSAVG_OUTBCASTPPSMIN_OUTBCASTPPSMAX_OUTBCASTPPS
02021062002722124184312184312184312448132844813284481328...0000000000
1202106205002722124383488383488383488141062561410625614106256...0000000000
22021062010002722124235192235192235192724388072438807243880...0000000000
32021062015002722124200032200032200032739856873985687398568...0000000000
42021062020002722124211264211264211264539952053995205399520...0000000000
\n", + "

5 rows × 58 columns

\n", + "
" + ], + "text/plain": [ + " YYYYMMDD HHMMSS MNG_NO IF_IDX AVG_INBPS MIN_INBPS MAX_INBPS \\\n", + "0 20210620 0 2722 124 184312 184312 184312 \n", + "1 20210620 500 2722 124 383488 383488 383488 \n", + "2 20210620 1000 2722 124 235192 235192 235192 \n", + "3 20210620 1500 2722 124 200032 200032 200032 \n", + "4 20210620 2000 2722 124 211264 211264 211264 \n", + "\n", + " AVG_OUTBPS MIN_OUTBPS MAX_OUTBPS ... MAX_INMCASTPPS AVG_OUTMCASTPPS \\\n", + "0 4481328 4481328 4481328 ... 0 0 \n", + "1 14106256 14106256 14106256 ... 0 0 \n", + "2 7243880 7243880 7243880 ... 0 0 \n", + "3 7398568 7398568 7398568 ... 0 0 \n", + "4 5399520 5399520 5399520 ... 0 0 \n", + "\n", + " MIN_OUTMCASTPPS MAX_OUTMCASTPPS AVG_INBCASTPPS MIN_INBCASTPPS \\\n", + "0 0 0 0 0 \n", + "1 0 0 0 0 \n", + "2 0 0 0 0 \n", + "3 0 0 0 0 \n", + "4 0 0 0 0 \n", + "\n", + " MAX_INBCASTPPS AVG_OUTBCASTPPS MIN_OUTBCASTPPS MAX_OUTBCASTPPS \n", + "0 0 0 0 0 \n", + "1 0 0 0 0 \n", + "2 0 0 0 0 \n", + "3 0 0 0 0 \n", + "4 0 0 0 0 \n", + "\n", + "[5 rows x 58 columns]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_total.head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "5388f7ca", + "metadata": {}, + "outputs": [], + "source": [ + "cols_to_remove = ['YYYYMMDD', 'HHMMSS']" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "cd234ff4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MNG_NOIF_IDXAVG_INBPSMIN_INBPSMAX_INBPSAVG_OUTBPSMIN_OUTBPSMAX_OUTBPSAVG_INPPSMIN_INPPS...MAX_INMCASTPPSAVG_OUTMCASTPPSMIN_OUTMCASTPPSMAX_OUTMCASTPPSAVG_INBCASTPPSMIN_INBCASTPPSMAX_INBCASTPPSAVG_OUTBCASTPPSMIN_OUTBCASTPPSMAX_OUTBCASTPPS
02722124184312184312184312448132844813284481328329329...0000000000
12722124383488383488383488141062561410625614106256546546...0000000000
22722124235192235192235192724388072438807243880424424...0000000000
32722124200032200032200032739856873985687398568371371...0000000000
42722124211264211264211264539952053995205399520388388...0000000000
\n", + "

5 rows × 56 columns

\n", + "
" + ], + "text/plain": [ + " MNG_NO IF_IDX AVG_INBPS MIN_INBPS MAX_INBPS AVG_OUTBPS MIN_OUTBPS \\\n", + "0 2722 124 184312 184312 184312 4481328 4481328 \n", + "1 2722 124 383488 383488 383488 14106256 14106256 \n", + "2 2722 124 235192 235192 235192 7243880 7243880 \n", + "3 2722 124 200032 200032 200032 7398568 7398568 \n", + "4 2722 124 211264 211264 211264 5399520 5399520 \n", + "\n", + " MAX_OUTBPS AVG_INPPS MIN_INPPS ... MAX_INMCASTPPS AVG_OUTMCASTPPS \\\n", + "0 4481328 329 329 ... 0 0 \n", + "1 14106256 546 546 ... 0 0 \n", + "2 7243880 424 424 ... 0 0 \n", + "3 7398568 371 371 ... 0 0 \n", + "4 5399520 388 388 ... 0 0 \n", + "\n", + " MIN_OUTMCASTPPS MAX_OUTMCASTPPS AVG_INBCASTPPS MIN_INBCASTPPS \\\n", + "0 0 0 0 0 \n", + "1 0 0 0 0 \n", + "2 0 0 0 0 \n", + "3 0 0 0 0 \n", + "4 0 0 0 0 \n", + "\n", + " MAX_INBCASTPPS AVG_OUTBCASTPPS MIN_OUTBCASTPPS MAX_OUTBCASTPPS \n", + "0 0 0 0 0 \n", + "1 0 0 0 0 \n", + "2 0 0 0 0 \n", + "3 0 0 0 0 \n", + "4 0 0 0 0 \n", + "\n", + "[5 rows x 56 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_total.drop(cols_to_remove,axis=1).head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "67749b8b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YYYYMMDDHHMMSSMNG_NOIF_IDXAVG_INBPSMIN_INBPSMAX_INBPSAVG_OUTBPSMIN_OUTBPSMAX_OUTBPS...MAX_INMCASTPPSAVG_OUTMCASTPPSMIN_OUTMCASTPPSMAX_OUTMCASTPPSAVG_INBCASTPPSMIN_INBCASTPPSMAX_INBCASTPPSAVG_OUTBCASTPPSMIN_OUTBCASTPPSMAX_OUTBCASTPPS
02021062002722124184312184312184312448132844813284481328...0000000000
1202106205002722124383488383488383488141062561410625614106256...0000000000
22021062010002722124235192235192235192724388072438807243880...0000000000
32021062015002722124200032200032200032739856873985687398568...0000000000
42021062020002722124211264211264211264539952053995205399520...0000000000
\n", + "

5 rows × 58 columns

\n", + "
" + ], + "text/plain": [ + " YYYYMMDD HHMMSS MNG_NO IF_IDX AVG_INBPS MIN_INBPS MAX_INBPS \\\n", + "0 20210620 0 2722 124 184312 184312 184312 \n", + "1 20210620 500 2722 124 383488 383488 383488 \n", + "2 20210620 1000 2722 124 235192 235192 235192 \n", + "3 20210620 1500 2722 124 200032 200032 200032 \n", + "4 20210620 2000 2722 124 211264 211264 211264 \n", + "\n", + " AVG_OUTBPS MIN_OUTBPS MAX_OUTBPS ... MAX_INMCASTPPS AVG_OUTMCASTPPS \\\n", + "0 4481328 4481328 4481328 ... 0 0 \n", + "1 14106256 14106256 14106256 ... 0 0 \n", + "2 7243880 7243880 7243880 ... 0 0 \n", + "3 7398568 7398568 7398568 ... 0 0 \n", + "4 5399520 5399520 5399520 ... 0 0 \n", + "\n", + " MIN_OUTMCASTPPS MAX_OUTMCASTPPS AVG_INBCASTPPS MIN_INBCASTPPS \\\n", + "0 0 0 0 0 \n", + "1 0 0 0 0 \n", + "2 0 0 0 0 \n", + "3 0 0 0 0 \n", + "4 0 0 0 0 \n", + "\n", + " MAX_INBCASTPPS AVG_OUTBCASTPPS MIN_OUTBCASTPPS MAX_OUTBCASTPPS \n", + "0 0 0 0 0 \n", + "1 0 0 0 0 \n", + "2 0 0 0 0 \n", + "3 0 0 0 0 \n", + "4 0 0 0 0 \n", + "\n", + "[5 rows x 58 columns]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_total.head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "dce7124b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YYYYMMDDHHMMSSMNG_NOIF_IDXAVG_INBPSMIN_INBPSMAX_INBPSAVG_OUTBPSMIN_OUTBPSMAX_OUTBPS...MAX_INMCASTPPSAVG_OUTMCASTPPSMIN_OUTMCASTPPSMAX_OUTMCASTPPSAVG_INBCASTPPSMIN_INBCASTPPSMAX_INBCASTPPSAVG_OUTBCASTPPSMIN_OUTBCASTPPSMAX_OUTBCASTPPS
318750320210626235500263562168561685616856314723147231472...0000000000
318750420210626235500263572155681556815568429204292042920...0000000000
318750520210626235500263582721832072183207218320103256103256103256...0000000000
318750620210626235500263592298562985629856393043930439304...0000000000
318750720210626235500263602161681616816168411604116041160...0000000000
\n", + "

5 rows × 58 columns

\n", + "
" + ], + "text/plain": [ + " YYYYMMDD HHMMSS MNG_NO IF_IDX AVG_INBPS MIN_INBPS MAX_INBPS \\\n", + "3187503 20210626 235500 26356 2 16856 16856 16856 \n", + "3187504 20210626 235500 26357 2 15568 15568 15568 \n", + "3187505 20210626 235500 26358 2 7218320 7218320 7218320 \n", + "3187506 20210626 235500 26359 2 29856 29856 29856 \n", + "3187507 20210626 235500 26360 2 16168 16168 16168 \n", + "\n", + " AVG_OUTBPS MIN_OUTBPS MAX_OUTBPS ... MAX_INMCASTPPS \\\n", + "3187503 31472 31472 31472 ... 0 \n", + "3187504 42920 42920 42920 ... 0 \n", + "3187505 103256 103256 103256 ... 0 \n", + "3187506 39304 39304 39304 ... 0 \n", + "3187507 41160 41160 41160 ... 0 \n", + "\n", + " AVG_OUTMCASTPPS MIN_OUTMCASTPPS MAX_OUTMCASTPPS AVG_INBCASTPPS \\\n", + "3187503 0 0 0 0 \n", + "3187504 0 0 0 0 \n", + "3187505 0 0 0 0 \n", + "3187506 0 0 0 0 \n", + "3187507 0 0 0 0 \n", + "\n", + " MIN_INBCASTPPS MAX_INBCASTPPS AVG_OUTBCASTPPS MIN_OUTBCASTPPS \\\n", + "3187503 0 0 0 0 \n", + "3187504 0 0 0 0 \n", + "3187505 0 0 0 0 \n", + "3187506 0 0 0 0 \n", + "3187507 0 0 0 0 \n", + "\n", + " MAX_OUTBCASTPPS \n", + "3187503 0 \n", + "3187504 0 \n", + "3187505 0 \n", + "3187506 0 \n", + "3187507 0 \n", + "\n", + "[5 rows x 58 columns]" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_total.tail(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "9a33b60a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "22745 25187\n", + "10784 13790\n", + "10751 13762\n", + "20633 13755\n", + "20542 13748\n", + " ... \n", + "14892 612\n", + "2869 533\n", + "26240 533\n", + "15259 455\n", + "26083 237\n", + "Name: MNG_NO, Length: 10686, dtype: int64" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_total['MNG_NO'].value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ceebd30", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/etc/Hamon_EDA.ipynb b/etc/Hamon_EDA.ipynb new file mode 100644 index 0000000..5a77ff3 --- /dev/null +++ b/etc/Hamon_EDA.ipynb @@ -0,0 +1,1270 @@ +{ + "cells": [ + { + "attachments": { + "a605f057-f69a-4b92-9208-56fa92cada49.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA5YAAAIuCAYAAADE5ZfSAAAgAElEQVR4AeydB5gUxdaGW1DBCEiSnEy/ehUFxYCKSBIxIBIkSk4CgmLCiGDAhKJiVlTAcM1iTtesmANiQlCCCAKigsTzP28ttfQ2PbOzCdiZr56nmZnuqurqt6qX+vqcOh2YkgiIgAiIgAiIgAiIgAiIgAiIgAgUgEBQgLIqKgIiIAIiIAIiIAIiIAIiIAIiIAImYalBIAIiIAIiIAIiIAIiIAIiIAIiUCACEpYFwqfCIiACIiACIiACIiACIiACIiACEpYaAyIgAiIgAiIgAiIgAiIgAiIgAgUiIGFZIHwqLAIiIAIiIAIiIAIiIAIiIAIiIGGpMSACIiACIiACIiACIiACIiACIlAgAhKWBcKnwiIgAiIgAiIgAiIgAiIgAiIgAhKWGgMiIAIiIAIiIAIiIAIiIAIiIAIFIiBhWSB8KiwCIiACIiACIiACIiACIiACIiBhqTEgAiIgAiIgAiIgAiIgAiIgAiJQIAISlgXCp8IiIAIiIAIiIAIiIAIiIAIiIAJpLSwvueQSGzduXMq9vGjRIuvVq5c9/vjjKZeJy/j333/brFmzbP369XGHs/fNmTPH/vrrr+zf+iICIiACIiACIiACIiACIiACxZFA2grLKVOmWBAE1r9//5T7BWFZtWpVK1eunP30008plwtnREz27NnTqlevbs8++2z4UI7vr776qtWpU8cJ2VWrVuU4Fv2xbNkye//99+3pp5/OdXvyySftxRdftO+//97WrVsXrSrl37Nnz7Z//vkn5fybOyPXlpdtc7dP5xMBERABERABERABERCBTCJQpMLyx9kL7a6pb+ZquSts4L/++qvVqlXLdt55Z/v222/zVP3EiROdID399NPzVM5nRiQiKhG1Y8eO9bs3+bzssstcnr333tsWL168yXG/A+vnMcccYzvttJPLT725bdtuu60Tx9dff72vJk+f999/v5UvX946d+5sa9euzVNZMr/yyivOUnzttddaXjasy0888YQlE9rTpk2zM844w4499lhr3LixHXXUUUk3n+fmm29OaRzOmDHDxo8fn6P9tOvWW281zv3BBx/YypUr88xEBURABERABERABERABEQgnQkUmbCcu2CJHdFurAX1Btio6wrmWprXDkDMIL4GDx6c16K2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EAEREIFiTUDCMoXue/PNN50oOuOMM+zcc891E9xosYkTJ1oQBDnE1++//26jR4/OLkt5v7388suuCiYalHvuuefs119/dd+7d+8erX6T30zQzz//fPvoo482OZbqjrvvvju7Pb5dfPbu3duJlg8++MBV9frrr7t2nXjiiTmqpr1MfsNl+T5kyBCbMmVKjrxr1661atWqWfXq1W3VqlU5jkV/cE2XXnrpJpNPhBb7maT59NVXX7m2MQHPLSFKDjzwQNt///1t+fLluWVPePy7776zXXbZxQ466CD766+/XD6EHmIRwRlNHFu9enWOrVWrVq7dUeFDv8K/atWq7jhjg61GjRqO9dy5c131//zzj+23335Wvnx5Y5z5hGhnUr3vvvtmly9ZsqQdf/zxm4yVs846y+V56qmnfPF8fyIEGI8vvvhibB3t2rVz53r//fdzHKftderUsZNOOinH/ugP2MLhlVdeiR4yHlpE+Z588skuPw96osfy82Dj559/toEDB2aPdR6SIOz59OMfAcc4f/zxx925+/Xrl6OtycbIww8/7B6O0FYSbdxnn33cOAuP92+++cYuvvjiTR40IKguuOAC+/zzz7PPicCFGUItnOLGIyJ0zz33tG222cZmzJixCTOuqzASonL77be3q6++Ora6tm3bujaHryOc8c8//7TLLrvMnn766fDu7O/0N9d85plnZu+j7TxoiP5NIgN/t2+//fYcD7t69erl6nj77bez6+BL3Di7+eabXV7+X4iOM377scZDw0MPPdR23nlnYywpiYAIiIAIiEA6EpCwTNKrWIKGDRvmJkJ77723s1DVrl3bSpUq5SY34aJ33XWXm2DwxN0nnmIzyWHyj3UrvPlJDiKAPC+88IIhGhABffv29VUk/LzjjjtcOSZZ+U2UDbfJf2eCSZuYYJH+97//ud/t27fPcSpvHfDl/Cdlq1Sp4qwOPNFHuGC92X333Z3gyU1Ywpw6nnjiiRznYxLPfoT+u+++6+rFEsa+VMT4H3/84QQbAheLXn4Twplzhie39N0OO+xge+yxxyai9f7773cCATHqt2233dZ22mknC1tFmAD36NHD1X399dfbrFmz3IaF1V8nFkomq1h+4F2zZk1btGhR9qUw/mgbwhXRTR2PPfaYcT76lYcBPjEZJu+zzz7rd+X785FHHnF19enTJ7aOLl26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REAECkxAwrLACFWBCIiACIiACIiACIiACIiACGQ2AQnLzO5/Xb0IiIAIiIAIiIAIiIAIiIAIFJiAhGWBEaoCERABERABERABERABERABEchsAhKWmd3/unoREAEREAEREAEREAEREAERKDABCcsCI1QFIiACIiACIiACIiACIiACIpDZBCQsM7v/dfUiIAIiIAIiIAIiIAIiIAIiUGACEpYFRqgKREAEREAEREAEREAEREAERCCzCUhYZnb/6+pFQAREQAREQAREQAREQAREoMAEJCwLjFAViIAIiIAIiIAIiIAIiIAIiEBmE5CwzOz+19WLgAiIgAiIgAiIgAiIgAiIQIEJSFgWGKEqEAEREAEREAEREAEREAEREIHMJiBhmdn9r6sXAREQAREQAREQAREQAREQgQITkLAsMEJVIAIiIAIiIAIiIAIiIAIiIAKZTUDCMrP7X1cvAiIgAiIgAiIgAiIgAiIgAgUmIGGZD4TLly+32bNn27p16/JU+rvvvrPWrVvbww8/HFvuiiuusI4dO9qSJUtij69Zs8aGDBliF154Yezx1atXu+NnnXVW7PGC7Hz66aetZcuWNnPmzFyrWbt2rc2aNcv++eefXPMmyzBp0iRr0aKFLVy4MFm2zXJsxYoV1q9fPxs3bpw732+//WadOnXK7sv169dbz549bcSIEZulPTqJCIiACIiACIiACIiACGxNBCQs89EbQ4cOtd12282++OKLPJV+7rnnLAgCGzx4cGy5I4880h1HgMalP/74w3beeWerX7++ITKjacGCBVamTBnbc889DaGTLHF8ypQp9uSTT+bIRr0PPPCAPfHEEzn2n3322a5tL7/8co79cT9effVV184bbrgh7nBK+7799ltXR8OGDXMI1F9//dXGjBlj5513np1zzjk5tttvvz1XsU/7x44da3/99VdK7fCZfvnlF9tmm23ssMMOc7s++OADx4M2+ITwpH9TYeTL6FMEREAEREAEREAEREAE0oGAhGU+evGkk05yAuKtt95KWhor14cffmjkY8MiifBo27Zt9r63334720LZvHlz23HHHe3777939S5dutTYt/vuu7utQoUKrjx1VK5cOXs/oo+EZa9KlSpOeOYmLLG4lS9f3urWrWt//vln9nXMnz/fdthhB2vcuLEtWrTIaB9t79Chgzv3a6+9lp030ReEKW1E/OU3eZH2/PPP56gCUUndMKlXr16OrUuXLoa1NFGaM2eOVatWzXbaaSebN29ejmx33313Nk/Pe++993ZWSizBiHbKNWnSxJWjX2nHqFGjsuuh/l133dUOOeSQWOGfnVFfREAEREAEREAEREAERCDNCEhY5qNDjz/+eCcqHn/88aSlsTzWqFHD5UWExG0lSpSwF154wdWD22dYWCJMETyIqauuuspuvvlmu//+++2+++6zm266ya688kp3DAshaeXKlVa9enU78MADc7VYYvlDnCKewi69uPmWLVvWEM/Tpk1zVrpwu994442k18zBO+64w11r165dc80bl+H333+3qlWrOoGMqAunkSNHurq/+uqr8O5cv1NPmzZtXFn4RdNHH33kWMLab7AsWbKkIcIR2ViLjz32WFc0TlhyYNCgQe4cL774YvQU+i0CIiACIiACIiACIiACaUtAwjKPXYuY3HbbbZ14OProow2rYqKEmEHA/fzzz27DVROR1r179+x9rNVEQJKiFstovaxb9NZPXDN9wlKJ6+o999zjXHQbNGiQq7CcO3eu1axZ01nwvOsrddx1111OQLGe0q8lpf19+vRxbc/NYokl8KCDDnJ5d9llF8stv7+G8CfuuXCKs3h6S+bHH38cLpLr94kTJ7o627dvn2ten+HEE0+0UqVKOUuwF5bHHXecO/zZZ5+5+sIWSw4wPmg7AlhJBERABERABERABERABDKFQFoKy3Xr1tsfy1bamiRukXntYITFpZde6kQDaxjPOOMM932//fZLeU0dlklER6LgOomEJcIOQYTFDFHLxlrKvn37OlGKYPX7qf/www9PSVjutddeziLpy/pP6sAqG07+2hMJRdZmPvLII85iSvnevXs74YoFFuvqv//+G64u6fdzzz3XccJiGk3dunWz0qVLZ7sLR4/H/Z4xY4bjhRUUlqtWrUppjSUMtt9++2yLJULZuwi/9NJLro1RYfnTTz+5czVt2lTusHGdoX0iIAIiIAIiIAIiIAJpSSDthOWvC/60ziMes9pNJ1i7IY/YnHmJLYqp9ChBXghCg1skggnx9+mnn7qiWPpwJ2U/wu+dd95JWqVfezhgwIDYfHHCEsHG+sbtttvOucViIWW75ppr3HkJHsO6QsQSa/xSXWOJxZL1hohkxJavFxGGK2yrVq1cZFdE62233WZY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mTNt9erVOfavXLnSvvrqK1eGa4uec82aNe5aFy1alKMcP3799dek17FJAe1wBJIJS/rj008/zR4/Tz75pJUqVcr69u2bvY9x9fvvv+egyXho0qSJ7bXXXla3bt3Y7eabb85RRj9EQAREYGsnIGG5tfeQ2lfkBCQsixyxTiAChU4gN2H56KOPWoMGDWy77bazIAisdOnSduSRRxr7fVq6dKkNHTrUqlSp4vKQr1atWnbNNdfY+vXrfTY7/PDDrUuXLtm/o1+uvPJKq1Gjhv3222/RQ+73559/brvssovxH65Pd911l+23337Z561QoYJ17tzZFi5c6LJMnjzZypUr50SiL/PKK69Y48aN3bXQ1pIlS1rz5s3tww8/9Fnsvffec9fcsmXLTYR069atrU+fPtl59SU1AsmE5XfffWc777xzdj/SL3HbxIkTc5xs6tSpLh/j6oILLojdXnvttRxl9EMEREAEtnYCEpZbew+pfUVOQMKyyBHrBCJQ6ASSCcvXX3/dTdqbNm3qrEZYh9jXpk0b81YgLH0DBw60EiVK2Lhx45xFkXwjR450ZcePH5/dZgRg27Zts39HvyAMEIFYPuPS+++/7+qcMmWKO4y4RXxg1cKSynnvu+8+a9Gihc2aNcvlueOOO2zbbbd1Fk12YKVEnNavX9/efPNNV+bVV1+1OnXqWM2aNW3BggWu3DPPPOPqpn5cMsMJYd2zZ8/wLn1PgUAyYYk1+v/ZOw9oKYqtCxtQREEUBMyiz5wwIygoYhazYgTDUkBRxKwYMaKCOSuYUVSWqL+YI5gFUcwJc87pmZ71r698p19N356+M5eZudMz+6zVd2a6K+6q7nt2nVOn3377bYfFGYvw/fff74kmBB7rN+OJWyyLGKEwFyCkNm7hNX0XAkJACGQVARHLrI6c2l0yBEQsSwalChICFUMgH7HE0rjNNtu4ZZZZxuFOmk8gc61atXJnnnlmgyS77babt0Ca+2KXLl3cTjvt1CCdnTj++ONdhw4d3Icffmincj6xKEISx40b588feuih3kqakyj24+qrr/aWyRdffNFfOfjggx1Wzbir7muvveb7ceqpp/p0d999t2vfvr23bIJBSGg22GADB0mSFIdAGrEMS5o8ebLr2bOnJ/bt2rVzl19+ufv111/DJNF3W1zAAr3DDju4fv36uX333dfPM35zXHnl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wmpDQMSy2kZE7RECjSMgYtk4RkpRGgRELEuDo0oRAkKg9hEQsaz9MVYPG0FAxLIRgHRZCFQhAiKWVTgoNdokEcsaHVh1SwgIgZIjIGJZckhVYNYQELHM2oipvULAORFLzYJKISBiWSmkVY8QEAJZR0DEMusjqPbPNAIiljMNoQoQAhVHQMSy4pDXbYUilnU79Oq4EBACRSIgYlkkYEpeewiIWNbemKpHtY+AiGXtj3G19LCaiOXvv//urrnmGvfUU09VCzxqRx0h8N5777mrr77affXVVwX1+t5773UPPvhgTtpffvnFXX/99e7NN9/MOV/Mj99++83dfPPN7u23326Qbfz48e65555rcJ4T1Hnddde5H3/8MfF6ISe//PJLd8UVV7hPPvmkkOQ+zcsvv+xuu+0299dffxWcJ6sJRSyzOnJqd8kQELEsGZQqSAhUDIHGiOWnn37qjj/+eLfSSiu5xRdf3K255pru7LPPdihGCMoNhGH55Zf310lD2jPPPLOB0vHTTz+5Cy+80K2zzjo+7XLLLeeOPvpo9+KLL7q///67Yn1WRc2DQGPEkjl1+OGHR3Opa9eu7oILLnAfffTRTDf4P//5jzv44IPdpZde6st65ZVX3CyzzOJ23XXXosvmnth2223dMsssE8157ovLL7/coajPjDz22GNu0003dR9//PHMFFNQXhT0bbbZxv3www8FpW+uRM8884zba6+93JJLLunxBh9IzTfffOObdP/997v+/fs3eN6Usr133XWX23PPPUtWB9gz/yZPnpzYzD/++MNBop599ln39NNPO56VXbp08b8599Zbb7l33nnHdejQIZrTSQVde+21bv/993d//vlndPn00093hx12mP/NPJtzzjndueeeG13nC8/1FVdc0R155JE55+3H6NGjXatWrXwb7Vz4yTN9qaWWiu4P/i+suuqq/n62Z/3DDz/sMeB/UFymT5/uNtlkE/fCCy/kXDrqqKNc+/bt3ddff51zvhZ/iFjW4qiqT0UhIGJZFFxKLASqAoE0Yvnhhx+6ZZdd1s0333xeETnuuOPcoEGDXNu2bT0hpAMffPCBm2OOOVzPnj0d1zkgEKa0YxlCfv75Z7flllv681wnHSRiiSWW8OdR/CW1jUAascQCsthii7mFF17YoTzaPGrdurUbMWLETAPz73//2yu5u+22my8L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Tw5KcO6ee+5xyy67rHv11VdzzvPj4IMPdksssYT797//7a+hYB900EFu4YUXdrPMMos/1lhjDXfLLbdEeSF+Cy64oLvpppuic/bl8MMPd5tuuqknsTvttFNUBmXNNttsOb9vuOEGyxZ9Xn311a5FixY56eacc043ZMiQHGWVPp9//vluxRVXjNJ26tTJ7bbbbu6VV16JyrMv5557rmvbtq17/PHH7VTO59NPP+369OkT1d26dWu33XbbuTfeeMO9+OKLjt+Gx6yzzhp95xzPVpT/Aw44wMWvLbXUUm7MmDFRXXvssUdOXvIzNjfeeGOUBqK61157+bHkOngwzg888ECUphxf0ojlIYcc0qBvCyywgLvgggui+UebIMnMgUUXXTTq59JLL+3I//nnn+c0+++//3b9+/f3aUPCGCYaP368W3fddaOyGOP999/fQSqvu+666Dw4xefX9ttv78dlvfXWy0lH2nXWWcc9/PDDvirI0VprrdUgTffu3d0TTzwRNSc+R7jXqGP69OlRmpn5AhFebrnlGrRjo402cs8//7wvGnLEnKIP4cE9xzw1efDBBx35LE27du38vZG2SGN50z4h6TvssENUbji3yQdxW3PNNd3RRx+dVkzFr/FMnH/++d2TTz5Zkbq//fZbx7OMRaGmiOXnWSupTgRELKtzXNSqCiIgYllBsFWVECgRAmnEcptttnErr7xyRAq7du3qFb6NN944Z2V+7NixrkOHDu7ll1/OaRVWJcjB8OHD/fk///zT7brrrp5AnHPOOe7ZZ591zzzzjNtxxx19uXfffbdPN23aNP/7qquuyimPH+RfZpllvJUJpYgyOIYOHermnntud/vtt0fnkixZhx56qFcAIcOW96yzzvL1nXrqqVF9kEqUZkiGpbvsssu8UmuEwRJjYenWrZtPf+CBB9rp6JN2tm/f3q222mpu4sSJvjzaCbG46667PDmZMmWKPw8xpX+bbLJJVC+4QnRXX311B4mx9vAJcaKdjz32mK9vhRVW8Ap/mKZv374+DedoK0Rqvvnmc9dff70vC5IA6T399NOjNpfjSxqx7NGjh+8f88HaPmjQIN9umxdY8/bee29/jrZauuOPP97jEic1WNeZf+CDEh6X+++/31+DyEAMKO/SSy/1+GAxg8RaHePGjfPkHwJr57DWQWZZFAjnCWMBsWShAesa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gw02cOhEeG5pnuk+0xzQHNAcSJ4DPC+HDBnit7C98MILIpZl04BUcJMRELFsMnTKKARqGgGU/FlmmcVbLeedd143zzzz6BAGJZ0D7O9v06aNX8CYbbbZfNn81lzTvaY5oDmgOdBwDvC/uGXLlv5/86RJk0Qsa1oLy2jnRCwzOnBqthAoMwLs48BiSQyAp556yvFPTIcwKPUcePLJJ12fPn3cSiut5B566CE3efJkzTPda5oDmgOaAwlzgP/FxEZp27atmzp1qohlmfUgFd8EBEQsmwCasgiBOkDgnnvu8dbKt956qw56qy42JwKDBg1y66+/fnM2QXULASEgBDKBAPEP2MKmPZaZGK76a6SIZf2NuXosBApBQFFhC0FJaUqBgKLClgJFlSEEhEA9IJA3KqyC99TD8Fd/H0Usq3+M1EIh0BwIiFg2B+r1WaeIZX2Ou3otBIRA8QiIWCZg9ttvv7kvv/zS/ec//0m4+s+pRx55xOEe88033+SkefbZZ90uu+ziunXr5g9e2RKGwz/zzDN9ZLmcTM65r776yn344YeO12vEhehTZ5xxhvv777/jl2r+t4hlzQ+xOigEmoSAiGWTYFOmJiAgYtkE0JRFCAiBukRAxDJh2AmXu+SSS+YQwniykSNHullnndVBfEzY2D///PP70OR77LGH44BgUtarr77qk6277rput912syzu3//+tzv99NO9PzIRDjm22247995770VpdtxxR8crMUhbbyJiWW8jrv4KgcIQELEsDCelmnkERCxnHkOVIASEQH0gIGKZMM4XXHCBjzb40ksvRVfZhLrmmmu6ZZZZxh8LLLCAW2ihhVwYOGLYsGGOULu//vprlG/GjBmuVatW7qKLLvLnevfu7fbdd9/o+tlnn+3J5EknneQee+wxx4AstthibtNNN3V//fWXTwcRXXnllUUsI9RK+0XvsSwtnipNCFQCARHLSqCsOkBAxFLzQAgIASFQGAIilgk4XXzxxW7uuef2EY3s8qeffurOOussN3z4cH9sttlmrkOHDjnE8t577/UvBd12223d0KFD3WGHHeY233xzt+iii7o333zTF7XRRhvlEMuNN97Y9erVy6rxn7fffrsP1Wt5dt99d7fKKquIWOagVLofIpalw1IlCYFKISBiWSmkVY+IpeaAEBACQqAwBEQsE3BKIpZYIV9//XX3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Sb/oy9YhEcsErY4XuPNqg7jFMolYfvzxxw5Lr+014xUF4XHAAQd46yfpTLBYvvLKK+7ZZ5/17+WbMmVKZLHEevn888/7awRNqUcRsazHUVefy4lArRDLu+66K3qfKO7VvJpGhzAo9RxgbvXr188vXrAoXOryVZ7mrOaA5kCtzAGel9dff71fjHvppZdELJOUuS233NIrL/F9PEnEkn86uLp27drVHXrooQ2OVVZZxQc5+eSTT5Kq8ucmT57sA53wLr3XX389b7p6uVBrxPLqq6+ul6FTP6sUATbW88oU7q0si+2xfPXVV7PcDbU9AwgMGDDAR7fmXbwSISAEhIAQyI8A751njyWBDmWxjOF0zTXXuNlnn90f7I8MA/gkEUuyn3zyya5Xr15u3XXXbXD07t3bDR8+PFbLPz8fe+wxt80227gOHTq4ESNGuGOOOcbv4cTKiTWzXqXWiOUll1ziI6USrEaHMKj0HCBK78033+z3i2V94er//u//fPCeadOm1evjUf2uEAKKClshoFWNEBACmUdAUWHzDOG1117rfYRxhR09erTfy0PAHpM4sSQqJiZgFEWUt3wH10n366+/+qLeeecdt9FGG/m6tthiC/fggw9aFY7BWW211bzFdM8992ywzzNKWMNfaoVY4tJMBEt8z3v27Om6deumQxhUfA706NHDv4d0rrnm8hvrs/zoELHM8uhlq+0iltkaL7VWCAiB5kNAxDKGPa4uZ599tieS2267reOVCsioUaP8uYEDB3ryeNxxx/ngPd98842/vtdee7kWLVrkvKsPImGb/sN39pHOSOqHH37o+vbt68aNGxdZRHlfH3stEerHyjVkyJCoLf5CnfypFWLJa2tat27trdlDhw7173bk/Y46hEEl5wBzjwUs3ivKnMyyiFhmefSy1XYRy2yNl1orBIRA8yEgYhnDHmK5yy67eLfUn376KecqrxHhPZVYHU844QRPLL/++muf5rnnnnPjx493Dz30kEPhuf32292ll17q5p57bsf+DH6HRz73LSyd66yzjuvTp09O3fX6o1aIJa+MWWSRRfym5nodS/W7OhBgb2Lnzp39K46qo0VNa4WIZdNwU67iERCxLB4z5RACQqA+ERCxTBj3tA369tqRuCusFXP//fdH75zEmtm2bVtHWPxiBFdJrKUS5wOMsAmYzcDlkn/961/eGp0WVGlm64YgL7zwwu6KK66Y2aKUXwjMFAK1EhVWxHKmpoEyF4GAiGURYCmpEBACdY2AiGUTh/+oo45yCy20kAvfYwkxIZrrWWed5UvlvZZbb721w0KQJE8//bRbZpllHMTGjqWWWsqTHN5faefsE0vmF198kVRUzZ6rFYuliGXNTtHMdUzEMnNDpgY3MwIils08AKpeCAiBzCAgYtnEoeJ1IlgjQ2L50UcfeTJ40UUXFVQqgXuOPPJId8QRR0QHv0866SR34oknRufsOhFnf/jhh4LKrpVEIpa1MpLqR7UgIGJZLSOhdmQFARHLrIyU2ikEhEBzIyBi2cQRALiDDz7Y/fbbb1EJEMsllljC7bfffu6BBx7wB3suifRqvx9++GH/guUok76kIiBimQqPLgqBohEQsSwaMmWocwRELOt8Aqj7QkAIFIyAiGXBUDWekP2XvMOSCLC4siYdhPl/8sknGy9MKTwCIpaaCEKgtAiIWJYWT5VW+wiIWNb+GKuHQkAIlAYBEcvS4BiV8t1337lPP/3Usd8y6eDa77//HqXXl3QERCzT8dFVIVAsAuUilhMmTHC77babu/jii/17fJPadcEFFzjeyfvoo48mXS7qXLmD93z55Zfe04R3FEvqGwERy/KN/1NPPeXefvttR7DDRx55pCj9CH1q8uTJ7s8//yxfA1WyEBACRSEgYlkUXEpcaQRELCuNeOH18WocXrcTuoOTm6jKKAm8lqfUwntd7d2xpS47rTzq/PXXX9OSZOZauYjlfffd5700Zp99dnfLLbc0wOOZZ56Jrt9www1+fzpzqKmSRiyvvPJKN3z48OjdwJdddpnr379/zp546n3ppZf8O4LZxhCXc88917Vr1859++230aVnn33WDRo0yPXo0cMRvZt3HrOYaMKe+wMOOCDRKwVMSP/333/7ffSUwbHpppu67bbbzm244Yb+N+fYOhEXgr3tuOOOboMNNojS8QqsV199NScpv9mOwR5+EwLJ8Yosq5MYAa+88krOAgBjwSuxqIN0m2++uQM3FkhpcyjcC7yL+ZprrglPR9+ZC9tss43HiLLAilgBIc48HxijzTbbLGoXr9kaO3ZsUeQiqrSMX9KI5a233upfD0Yf6SvjM2LECI9b2CSC+PHO2vA1ZtOnT4/mE+N/xhlnuI8//jjM5tPzLmveP0v5jA91hvPOMvBe7H333dfxLuwk4b7YcsstI7x79+7tRo4cmfNsI0Agc5xr1Mex++67+y09SWWG55hTRMz/+eefo9N8hwAyB5lLfOf4/PPPPSFcddVVHfORhan555/f0QeEBXjShQv0/A4Xes4//3w333zz5cyrqGJ9EQJCoFkQELFsFthVaaEIiFgWilTl06GAEMWY97eGgnLRpUsX/07X8Hz4HWUdRduUiPBavu+sSqOEnnrqqT4Jigck6eabb85RkC0/BJc67rjjDk92OY9yg+Jq5BRF5aqrrnLvvvuuZfOf5IW4vPzyy/73eeed5xVGiG3WpVzEElz22WcfTx5RFnl3qwkkYquttvLXeE/wnXfe6YlPnLBY+kI+04glSjgRt23RY6211vJ1Dxs2LKfom266ybVu3drF3yvM3OrWrZu3wFqGq6++2kGaV1ttNbfzzjt7Bb99+/Z+rhsZgKiyBeLyyy+3bNFn3759/f0CKWM+UQbH8ssv7/NAMO3cE088EeWzLyjslA2Olm6FFVbw7acfJvxTJx17+5EXX3zRB5XjXrV8K6+8so8HYMHnwAniTb5NNtnEp4MYEqAO0htfAID4knbZZZd19gouq5/PPfbYw18nr9W5wAIL+DHBOoVAGFq1auXPWRow4N3PkFosxtUiacQSAkY/dtppJ99X+rzooot6zFmIMCGSfMuWLaNn3rhx43xfw/lEvo033tiyeAyYh/PMM48fB3BifOacc04f4C9K+N8vRKRnXHbdddf4JT+GK664omPOGt6MMWVR5/fff+/zEBeCMrp27Rql6969uz8HMbZ7Kqzgtddec2PGjPH39frrr++JLa/Wokxet8Z9w7hSbosWLRxbgohHATled911/eIOixrMkRkzZviisURaHvJx0Fa8IsxCSX9JE39+h23TdyEgBCqLgIhlZfFWbUUiIGJZJGBlTo5S/PrrrzsUibvuusv/sz/++OP9b86xOj1lyhTXoUMHb/3I15znnnvOKxgoI4UKbpQouqzyI++9956bbbbZfBtMiQ7LMgvavPPOG61oQzJRUB577DGfFIsMv1nFD0kOCs/iiy/uLSokRHFB6cESkXUpJ7HkfmXswfTYY4+NLE8ojbPOOqtXJi+99FLv8jazEa7TiOX222/vCaApwSjGWB9pG0TLBOWe98vanLLzuOfRB+YLwgII79OFFIdE6vnn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ZpkILDACvYjlLrvsUj3wgQ/sEMv//u//ru5zn/tUd7rTnSovvZCPfOQjtcfvuuuui1P1JxK27LLLVkEYhcXy6hyzZ9hxAAAgAElEQVR55JFT0lHEkTHeJ6GuSMLtbne7itLeFARSWqGypSChd77znauf/vSn5elp/7/iFa+o1ltvvWnXlwlf9KIXVRtvvHGH0PgNkV1//fWrPfbYo04qDHOttdaqeNpK+djHPlaTmKhz+duk/9+LWD760Y+uHv/4x/eEiFf8KU95ypQ0+txyyy1XnXzyyfX5K664orr97W9fffKTn5yS7sADD6xJ/49//OMp5+f6JfqI8Nxu8oUvfKH64he/WLnnW97yluqEE06ow7h//vOf1954/R4ZffOb31x99atf7WTz7W9/uzrmmGPq835vhmF7ZqVRd9fqcymJQCIwXggksRyv9szazAGBJJZzAC0vSQSWGIHZEMstttiiDink+eE9MpeNdCOWz3jGM2oPE1JGeBMRzbaQ2be//e21J/FHP/pRddNNN82aWL7jHe+oiYNre0kQy6ayXl6z77771iGNzXmh6v+CF7ygTopYCvEVnlnKVVddVZPniy66qDyd/1dVNV9i+fCHP7ziOS5FO/AuI20kiKU+WcqJJ55YGx70r6YcddRR1T3vec9px73vfe8KOWwTxNI7r5c89alPrQ0xO+20U3XXu961fmaEgn/mM5+phPHyvrvvOuusU3v95XX++efX/UqdnOeNFSoeHnBklNFj2223rYQJS7Pbbrv1Kkb+lggkAiOIQBLLEWy0LPJgEUhiOVg8M7dEYDEQmA2xNM/QnEmeRwSRsk6Es5qjWHoseQ7XXXfdmohGPXiNeP3avIrh6fv6179ee2Nm67Hsl1gefPDBNYHdc88967KZe+cIj5eyBrHkWQoxv1I45Rvf+Mb6lIVamsTyV7/6VbXrrrvWczMjNDOuz8/exPIJT3hCHTb90pe+dEq7lJ5HxFLocYjFkw466KC6XYSgkiCW+mSIOY9IogOxa8o555xTCZFuHq985StbjSCuf9nLXlZ77s07jj7ks/Sym4Orzxx//PFTbins2vnHPe5xVdnHkEfPjNDw8KxecskldZi5vInFgbxrEU+/pSQCicB4IpDEcjzbNWs1CwSSWM4CrEyaCAwJArMlli95yUvqkvM+WahESOrZZ589jVieeeaZ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BJJYjmzTZcEHhUASy0EhmfkkAouHwGIQy7///e/VP//5z8WrVN5pKBFIYjmUzZKFmicCObbNE8C8vBWBJJatsOTJSUIgieUktXbWdVwQ6EUsv/Wtb1VXX311p6o33nhjdckll3S+xz+/+tWvqi9+8YvV73//+zjV+fzUpz5Vbb311tXPfvazzjn/XHHFFdUnP/nJ+rj55pun/PaXv/ylzu8nP/nJlPO+fO9736u+/vWv1+evvPLKTh7nnHNO9ZnPfKZyv8j3hz/84bTrf/rTn9bpbrnllmm/OfHzn/+8/v1HP/rRtN9d4x7yh8NvfvObaWmcUP7Pfe5zFVy6yV//+tc6D3nJ88c//nGd9M9//nN18cUXd+rw6U9/ujr33HM737XXH/7wh+oXv/jFlPPy+cIXvjDldvArr5XmS1/60pQ08eXLX/5yfQ/5f/vb347TA/3sRSz1ATh0w/Q73/lO19+/8Y1vVMqtfpdffnn1t7/9rbXcv/zlL+t2gX03gWu0sXaIPu28tnAPB1zL7xdddFFtPNE/y/PSfvWrX51yO/g200SfLhPqR9EXzjvvvE4fKdPM5/8bbrhhWjmcKwW2nq2ot0/jQFN+97vfVZ/97GfrdBdccEHPvt+8ttf3P/7xj532uP7663slHehvv/3tb+sx6k9/+lPXfLXPXnvtVW2//fadftI1cf6QCMwSgSSWswQsk48fAkksx69Ns0bjj0AvYvn0pz+92mKLLTqKOgVqmWWWqc4+++wpwHgBrr322tXXvva1Ked92X333asHPOABVSjzFFf5rLbaatXtbne7atlll63ufve7V29605s6137zm9+sll9++eqUU07pnIt/9txzz+ohD3lITd6e9axn1XnIR7ni8N3xwQ9+MC7rfL71rW+t0+2www4VT2pT9t577/r3Aw88cMpPb3vb26oNNtigWmGFFeq873CHO1T3ve99qw996ENT0vnykY98pM7jiCOOmPabE0j4VlttVa200kp1XvLcZJNNqjPOOKMmVpttttm0esFJnVZeeeXqu9/9bvXmN7+5vkec95v8nv/851fIM3nVq141LY3rETxEiXz/+9+vdtlll+pOd7pTnf9yyy1Xt8drX/va+vdB/ulFLJ/5zGfWZT3kkEOm3RKRfvjDH17//oEPfKDzOxK677771n3v9re/fV1+/Ur/gHFTAg+k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JgKJwCgikMRyFFstyzxQBJJYDhTOzCwRWBQEklguCsx5k6qqklhmN0gEEoFEoD8Eklj2h1OmGmMEkliOceNm1cYWgSSWY9u0Q1exJJZD1yRZoEQgERhSBJJYDmnDZLEWD4EklouHdd4pERgUAkksB4Vk5jMTAkksZ0Iof08EEoFE4F8IJLHMnjDxCCSxnPgukACMIAJJLEew0Ua0yEksR7ThstiJQCKw6AgksVx0yPOGw4ZAEstha5EsTyIwMwILTSx/97vfVdddd1315z//eebCZIqxRiCJ5fTm/c1vflNdf/311T//+c8pP37/+9+vvvvd704518+X73znO9VPf/rT1qS/+tWvqhtuuKH6+9//PuX3X//619WNN95Y/eMf/5hyvt8vrv/6178+Ld9+r59Nup/97GfVzTffPJtLhirt73//+7q9//SnP825XMZS7TjbMfWvf/1rfd0f/vCHrvf+4x//WH3lK1+pvvjFL3Y9fvzjH3e9vu0H/epb3/pW9dvf/rbt5+ob3/hGpV1LgY/3xnxwKvMbxf+TWI5iq2WZB4pAEsuBwpmZJQKLgkAvYvnxj3+8OvnkkzvlOPPMM6tDDjmkQhZLuemmm6ojjzyy+slPflKerv93/d3udrfq5z//eec3yu+b3/zm6n/+53/q44wzzpiilFJUjzjiiOraa6/tXBP/nH/++dVpp51Wfz3hhBM6eey9997VS1/60uqFL3xh5xzlqClf/epXq1e84hW10lL+RqE65phjqiuuuKI+7fMtb3nLtLr+7W9/q9z38ssvr9NR0tVxn3326dz3BS94QQW7kL/85S/1NcoYdZbmE5/4RCTpfF5wwQXVi170ojrdq1/96uqqq66aRjo6iUfsn17E8txzz61e85rXTOknqveDH/yg7lu33HJLXduzzjqrete73jWt5vrXUUcdVX3ve9+rf/vlL39ZvelNb6r23HPPDuba6LLLLutcS5k99NBDqz322KOTZt999+20bSSkGH/oQx+qtJn2O/zwwyt9eK6iz1DyHfrS2muvXZONOIdkPu95z6ue8pSntN6Csv2Od7yjuvDCC6f8rp898IEPrPv3lB/+/eUDH/hAte6661YIZiknnnhidY973KO69dZby9NT/tcvAyfPSUkSTjrppOoud7lL9cMf/nDKNfHlF7/4RfXOd76zXrwJfq961auq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rw499NDq1ltvravwyle+stpqq62qn/3sZzOqdNlll1VPfOITq5/+9Kczrvsij7vc5S4dYimvj370o9UOO+xQ3eMe96juec97Vs94xjOqH/7wh520v/rVr6rHPe5x1ac//enOtfhw2mmnVc95znPqOh122GF1HvK53/3uVz3sYQ+r1ltvvc61T3ziE5Gsc77wwgurjTbaqFp33XU78TbbbLPq4x//ePW///2vjnfuuefWeZVxtthii+pTn/pUJx8fPve5z1W77LJLpx37779/9dWvfnVGnPzyfwj0Ipann3569eAHP7geD/rTsdtuu1Vf+9rXOhm8+c1vrh70oAd1+k2cPfbYo/rWt77VifOf//ynWrZsWbXpppvW8YyLo48+uvrxj3/cibPQD8anfl9//fU7dfH5Na95TfXXv/51odnX6Y0jz9Qvf/nLeef397//vbryyiurv/3tb615/Pvf/648R/5/B+6eyWc+85nV9ddf35puITe+8Y1vVHvttVenPO30rP/3v/9dSLaLkva1r31tdeCBBy5KWVnIdCOQxHK6+z9bX1X1P6YlS5ZU/ulmSAQSgfFAoBexZNgz9v/5z3/Wjdlkk00qzziyWYazzjqrutOd7lQbseV1hu1DHvKQ6lnPelbnMqIpjyc/+ckVI40x/oAHPKBae+21q6uvvrqOd8UVV9Rx3vWud3XSxQcG6QYbbFD94x//qBBAeTh22mmnOs3znve8zrXIL9I6v+AFL6hWWWWV6sUvfnEn3pOe9KRqpZVWqt7//vfXUZ/97GdXq666avWyl72sE+fxj398tfLKK1dnn312Hefd7353nWb33XfvxNlyyy0rRxDUstz8XFW9iOW2225bk0rjIfoU4b/zne9cffvb367h23zzzav73Oc+nfviPepRj6rudre7dcaOSQfj66CDDqrjmQwxXhClQYVLL720LsNYjLo+97nPrcfDPvvsM5D+Nxa145vf/Oa8q22yBjYlOW9m9vvf/766wx3uUG299dadthxzzDE16TMB88c//rGZZEHfTezc7na3q5YuXdopb+edd67uf//7D7ysBVW0JbH31r3uda/OZFtLtLycCCwYgSSWC4YwMxh3BFKxHPcezPpPIwK9iOVTnvKU6pGPfGSHWFIrGfZI5Be+8IUOXMgWda9J5Ch6jGNngaG75pprVi984Qs7aX24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" + } + }, + "cell_type": "markdown", + "id": "21770ffe", + "metadata": {}, + "source": [ + "![image.png](attachment:a605f057-f69a-4b92-9208-56fa92cada49.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "617dbb54", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pandas as pd\n", + "import glob" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "9b4fead4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/repo/projects/HAI_timeseries/notebook/CES'" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "os.getcwd()" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "d4518761", + "metadata": {}, + "outputs": [], + "source": [ + "data_path = '/repo/projects/HAI_timeseries/Hamon_dataset/'\n", + "read_file = 'total_df.csv'" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "69d77230", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'pd' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata_path\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mread_file\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'pd' is not defined" + ] + } + ], + "source": [ + "df = pd.read_csv(data_path+read_file)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31cb8a56", + "metadata": {}, + "outputs": [], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a4033a2", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99b9100d", + "metadata": {}, + "outputs": [], + "source": [ + "df['HHMMSS'].value_counts(sort = False).plot.bar(title='My Title')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ad261ce", + "metadata": {}, + "outputs": [], + "source": [ + "df['MNG_NO'].value_counts(sort = False).plot.bar(title='My Title')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fa49b65", + "metadata": {}, + "outputs": [], + "source": [ + "df['MNG_NO'].value_counts(sort = False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c98808a", + "metadata": {}, + "outputs": [], + "source": [ + "for col in df.columns:\n", + " print(f'{col} : {len(df[col].unique())}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5a4e9b1", + "metadata": {}, + "outputs": [], + "source": [ + "len(df['MNG_NO'].unique())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8ad2720", + "metadata": {}, + "outputs": [], + "source": [ + "df.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43e80a22", + "metadata": {}, + "outputs": [], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5dfd123", + "metadata": {}, + "outputs": [], + "source": [ + "df.tail()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3689bac", + "metadata": {}, + "outputs": [], + "source": [ + "desc = pd.DataFrame(df.describe())\n", + "desc.to_csv('description.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecc8bd99", + "metadata": {}, + "outputs": [], + "source": [ + "df['YYYYMMDD'].unique()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e481efa2", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib as mpl\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7575efab", + "metadata": {}, + "outputs": [], + "source": [ + "from collections import Counter" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2212c391", + "metadata": {}, + "outputs": [], + "source": [ + "date_cnt = Counter(df['YYYYMMDD'])\n", + "\n", + "# Change Counter to Dict\n", + "for key, value in date_cnt.items():\n", + " date_cnt[key] = value" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "427cde29", + "metadata": {}, + "outputs": [], + "source": [ + "date_cnt.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af6404c5", + "metadata": {}, + "outputs": [], + "source": [ + "date_cnt.values()" + ] + }, + { + "cell_type": "markdown", + "id": "4835a31d", + "metadata": {}, + "source": [ + "## Get Count for Each Date" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa3ef41f", + "metadata": {}, + "outputs": [], + "source": [ + "plt.title(\"Bar Chart\")\n", + "\n", + "x = list(date_cnt.keys())\n", + "y = list(date_cnt.values())\n", + "\n", + "xlabel = list(date_cnt.keys())\n", + "\n", + "plt.bar(x, y)\n", + "\n", + "plt.xticks(x, xlabel, rotation = 75)\n", + "\n", + "plt.xlabel(\"date\")\n", + "plt.ylabel(\"cnt\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "096b1bb6", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "cols = list(df.columns)\n", + "cols" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f879545b", + "metadata": {}, + "outputs": [], + "source": [ + "vis_cols = []\n", + "\n", + "for col in cols:\n", + " if ('MIN' in col) or ('MAX' in col) or ('AVG' in col):\n", + " i, j = col.split('_')\n", + " vis_cols.append(j)\n", + "\n", + "print(vis_cols)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "199c8d95", + "metadata": {}, + "outputs": [], + "source": [ + "vis_cols = list(set(vis_cols))\n", + "print(vis_cols)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07e3d9bf", + "metadata": {}, + "outputs": [], + "source": [ + "print(cols)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64e8097f", + "metadata": {}, + "outputs": [], + "source": [ + "check_cols = ['BPS', 'DISCARD', 'ERR', 'NUPPS', 'PPS']" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "79a2ad40", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[20210620, 20210621, 20210622, 20210623, 20210624, 20210625, 20210626]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dates = list(date_cnt.keys())\n", + "dates" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "2d0de5f3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YYYYMMDD
020210620
120210620
220210620
320210620
420210620
\n", + "
" + ], + "text/plain": [ + " YYYYMMDD\n", + "0 20210620\n", + "1 20210620\n", + "2 20210620\n", + "3 20210620\n", + "4 20210620" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dates_df = pd.DataFrame(df['YYYYMMDD'])\n", + "dates_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "5a96b6fa", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MIN_OUTERRMAX_OUTERRAVG_OUTERR
0000
1000
2000
3000
4000
............
23195123000
23195124000
23195125000
23195126000
23195127000
\n", + "

23195128 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " MIN_OUTERR MAX_OUTERR AVG_OUTERR\n", + "0 0 0 0\n", + "1 0 0 0\n", + "2 0 0 0\n", + "3 0 0 0\n", + "4 0 0 0\n", + "... ... ... ...\n", + "23195123 0 0 0\n", + "23195124 0 0 0\n", + "23195125 0 0 0\n", + "23195126 0 0 0\n", + "23195127 0 0 0\n", + "\n", + "[23195128 rows x 3 columns]" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[['YYYYMMDD','MIN_OUTERR','MAX_OUTERR','AVG_OUTERR']].iloc[:,1:]" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "856b12e8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 0\n", + "1 0\n", + "2 0\n", + "3 0\n", + "4 0\n", + " ..\n", + "23195123 0\n", + "23195124 0\n", + "23195125 0\n", + "23195126 0\n", + "23195127 0\n", + "Name: MIN_OUTERR, Length: 23195128, dtype: int64" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[['MIN_OUTERR','MAX_OUTERR','AVG_OUTERR']].iloc[:,0]" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "98f07a03", + "metadata": {}, + "outputs": [], + "source": [ + "save_path = '/repo/projects/timeseries_anomaly/EDA/results'" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "15a93a5d", + "metadata": {}, + "outputs": [], + "source": [ + "#vis_cols = ['INERR', 'OUTDROP', 'INNUPPS', 'OUTNUPPS', 'INDISCARD', 'INBCASTPPS']" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "078c6ecb", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "vis_col: INERR\n", + ">>> plotting 20210620\n", + ">>> plotting 20210621\n", + ">>> plotting 20210622\n", + ">>> plotting 20210623\n", + ">>> plotting 20210624\n", + ">>> plotting 20210625\n", + ">>> plotting 20210626\n", + "vis_col: OUTDROP\n", + ">>> plotting 20210620\n", + ">>> plotting 20210621\n", + ">>> plotting 20210622\n", + ">>> plotting 20210623\n", + ">>> plotting 20210624\n", + ">>> plotting 20210625\n", + ">>> plotting 20210626\n", + "vis_col: INNUPPS\n", + ">>> plotting 20210620\n", + ">>> plotting 20210621\n", + ">>> plotting 20210622\n", + ">>> plotting 20210623\n", + ">>> plotting 20210624\n", + ">>> plotting 20210625\n", + ">>> plotting 20210626\n", + "vis_col: OUTNUPPS\n", + ">>> plotting 20210620\n", + ">>> plotting 20210621\n", + ">>> plotting 20210622\n", + ">>> plotting 20210623\n", + ">>> plotting 20210624\n", + ">>> plotting 20210625\n", + ">>> plotting 20210626\n", + "vis_col: INDISCARD\n", + ">>> plotting 20210620\n", + ">>> plotting 20210621\n", + ">>> plotting 20210622\n", + ">>> plotting 20210623\n", + ">>> plotting 20210624\n", + ">>> plotting 20210625\n", + ">>> plotting 20210626\n", + "vis_col: INBCASTPPS\n", + ">>> plotting 20210620\n", + ">>> plotting 20210621\n", + ">>> plotting 20210622\n", + ">>> plotting 20210623\n", + ">>> plotting 20210624\n", + ">>> plotting 20210625\n", + ">>> plotting 20210626\n" + ] + } + ], + "source": [ + "for vis_col in vis_cols:\n", + " print(f'vis_col: {vis_col}')\n", + " tmp_cols = []\n", + " \n", + " for col in cols:\n", + " #print(f'>>>>>col: {col}')\n", + " if vis_col in col:\n", + " tmp_cols.append(col)\n", + " \n", + " #print(tmp_cols)\n", + " #print('--------------------')\n", + " tmp_df = df[tmp_cols]\n", + " \n", + " # make tmp dataframe\n", + " tmp_df = pd.concat([dates_df, tmp_df], axis = 1)\n", + " \n", + " # for dates\n", + " for date in dates:\n", + " print(f'>>> plotting {date}')\n", + " \n", + " # use data at certain date\n", + " date_df = tmp_df[tmp_df['YYYYMMDD']==date].iloc[:,1:]\n", + " \n", + " criteria = ['MAX', 'MIN', 'AVG']\n", + " \n", + " for c in criteria:\n", + " \n", + " if c == 'AVG':\n", + " plot_df = date_df.iloc[:,0]\n", + " elif c == 'MIN':\n", + " plot_df = date_df.iloc[:,1]\n", + " elif c == 'MAX':\n", + " plot_df = date_df.iloc[:,2]\n", + " \n", + " # define fig\n", + " fig = plt.figure()\n", + "\n", + " plot_df.plot(figsize = (12, 6))\n", + "\n", + " plt.title(f'{c}_{vis_col}({date}) ')\n", + "\n", + " plt.savefig(save_path+ f\"/{c}_{vis_col}_{date}.png\", dpi=200)\n", + " \n", + " plt.close('all')" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "ee353892", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "vis_col: INERR\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0009929763219236904\n", + ">> MAX(MAX): 103\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0009929763219236904\n", + ">> MIN(MAX): 103\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0009929763219236904\n", + ">> AVG(MAX): 103\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.1070327038198467\n", + ">> MAX(MAX): 9360\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.1070327038198467\n", + ">> MIN(MAX): 9360\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.1070327038198467\n", + ">> AVG(MAX): 9360\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.21545382251356252\n", + ">> MAX(MAX): 12166\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.21545382251356252\n", + ">> MIN(MAX): 12166\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.21545382251356252\n", + ">> AVG(MAX): 12166\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.1899605151255562\n", + ">> MAX(MAX): 20995\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.1899605151255562\n", + ">> MIN(MAX): 20995\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.1899605151255562\n", + ">> AVG(MAX): 20995\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.3504950319532711\n", + ">> MAX(MAX): 87505\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.3504950319532711\n", + ">> MIN(MAX): 87505\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.3504950319532711\n", + ">> AVG(MAX): 87505\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.09246079843196818\n", + ">> MAX(MAX): 16707\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.09246079843196818\n", + ">> MIN(MAX): 16707\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.09246079843196818\n", + ">> AVG(MAX): 16707\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.013125300391402939\n", + ">> MAX(MAX): 3539\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.013125300391402939\n", + ">> MIN(MAX): 3539\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.013125300391402939\n", + ">> AVG(MAX): 3539\n", + "vis_col: OUTDROP\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "vis_col: INNUPPS\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.4232476784349255\n", + ">> MAX(MAX): 230423\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.4232476784349255\n", + ">> MIN(MAX): 230423\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.4232476784349255\n", + ">> AVG(MAX): 230423\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.3255765156290704\n", + ">> MAX(MAX): 4693\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.3255765156290704\n", + ">> MIN(MAX): 4693\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.3255765156290704\n", + ">> AVG(MAX): 4693\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.300698597051876\n", + ">> MAX(MAX): 3564\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.300698597051876\n", + ">> MIN(MAX): 3564\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.300698597051876\n", + ">> AVG(MAX): 3564\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.3138820131438875\n", + ">> MAX(MAX): 6472\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.3138820131438875\n", + ">> MIN(MAX): 6472\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.3138820131438875\n", + ">> AVG(MAX): 6472\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.414565846192937\n", + ">> MAX(MAX): 8387\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.414565846192937\n", + ">> MIN(MAX): 8387\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.414565846192937\n", + ">> AVG(MAX): 8387\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.3606745082676048\n", + ">> MAX(MAX): 3692\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.3606745082676048\n", + ">> MIN(MAX): 3692\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.3606745082676048\n", + ">> AVG(MAX): 3692\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.4019500500077176\n", + ">> MAX(MAX): 4121\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.4019500500077176\n", + ">> MIN(MAX): 4121\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.4019500500077176\n", + ">> AVG(MAX): 4121\n", + "vis_col: OUTNUPPS\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 2065.437395895265\n", + ">> MAX(MAX): 33784710\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 2065.437395895265\n", + ">> MIN(MAX): 33784710\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 2065.437395895265\n", + ">> AVG(MAX): 33784710\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 10884.217727320281\n", + ">> MAX(MAX): 45275418\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 10884.217727320281\n", + ">> MIN(MAX): 45275418\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 10884.217727320281\n", + ">> AVG(MAX): 45275418\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 10274.470403238776\n", + ">> MAX(MAX): 34360111\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 10274.470403238776\n", + ">> MIN(MAX): 34360111\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 10274.470403238776\n", + ">> AVG(MAX): 34360111\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 10379.628168063316\n", + ">> MAX(MAX): 49227501\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 10379.628168063316\n", + ">> MIN(MAX): 49227501\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 10379.628168063316\n", + ">> AVG(MAX): 49227501\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 10318.102998850687\n", + ">> MAX(MAX): 46340093\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 10318.102998850687\n", + ">> MIN(MAX): 46340093\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 10318.102998850687\n", + ">> AVG(MAX): 46340093\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 9422.836515565848\n", + ">> MAX(MAX): 32470807\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 9422.836515565848\n", + ">> MIN(MAX): 32470807\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 9422.836515565848\n", + ">> AVG(MAX): 32470807\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 2315.964770284498\n", + ">> MAX(MAX): 26240727\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 2315.964770284498\n", + ">> MIN(MAX): 26240727\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 2315.964770284498\n", + ">> AVG(MAX): 26240727\n", + "vis_col: INDISCARD\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 11.453699935354793\n", + ">> MAX(MAX): 8403755\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 11.453699935354793\n", + ">> MIN(MAX): 8403755\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 11.453699935354793\n", + ">> AVG(MAX): 8403755\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 102.17135060146234\n", + ">> MAX(MAX): 3169587\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 102.17135060146234\n", + ">> MIN(MAX): 3169587\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 102.17135060146234\n", + ">> AVG(MAX): 3169587\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 109.02586151696624\n", + ">> MAX(MAX): 3894820\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 109.02586151696624\n", + ">> MIN(MAX): 3894820\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 109.02586151696624\n", + ">> AVG(MAX): 3894820\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 124.03730567319344\n", + ">> MAX(MAX): 3365716\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 124.03730567319344\n", + ">> MIN(MAX): 3365716\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 124.03730567319344\n", + ">> AVG(MAX): 3365716\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 129.86653843994765\n", + ">> MAX(MAX): 9742979\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 129.86653843994765\n", + ">> MIN(MAX): 9742979\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 129.86653843994765\n", + ">> AVG(MAX): 9742979\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 101.42783862050769\n", + ">> MAX(MAX): 3252166\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 101.42783862050769\n", + ">> MIN(MAX): 3252166\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 101.42783862050769\n", + ">> AVG(MAX): 3252166\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 16.78371724870965\n", + ">> MAX(MAX): 877271\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 16.78371724870965\n", + ">> MIN(MAX): 877271\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 16.78371724870965\n", + ">> AVG(MAX): 877271\n", + "vis_col: INBCASTPPS\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n" + ] + } + ], + "source": [ + "for vis_col in vis_cols:\n", + " print(f'vis_col: {vis_col}')\n", + " tmp_cols = []\n", + " \n", + " for col in cols:\n", + " #print(f'>>>>>col: {col}')\n", + " if vis_col in col:\n", + " tmp_cols.append(col)\n", + " \n", + " #print(tmp_cols)\n", + " #print('--------------------')\n", + " tmp_df = df[tmp_cols]\n", + " \n", + " # make tmp dataframe\n", + " tmp_df = pd.concat([dates_df, tmp_df], axis = 1)\n", + " \n", + " # for dates\n", + " for date in dates:\n", + " print(f'> plotting {date}')\n", + " \n", + " # use data at certain date\n", + " date_df = tmp_df[tmp_df['YYYYMMDD']==date].iloc[:,1:]\n", + " \n", + " criteria = ['MAX', 'MIN', 'AVG']\n", + " \n", + " for c in criteria:\n", + " \n", + " if c == 'AVG':\n", + " plot_df = date_df.iloc[:,0]\n", + " plot_avg = plot_df.mean()\n", + " plot_min = plot_df.min()\n", + " plot_max = plot_df.max()\n", + " print(f'>> AVG(MIN): {plot_min}')\n", + " print(f'>> AVG(AVG): {plot_avg}')\n", + " print(f'>> AVG(MAX): {plot_max}')\n", + "\n", + " elif c == 'MIN':\n", + " plot_df = date_df.iloc[:,1]\n", + " plot_avg = plot_df.mean()\n", + " plot_min = plot_df.min()\n", + " plot_max = plot_df.max()\n", + " print(f'>> MIN(MIN): {plot_min}')\n", + " print(f'>> MIN(AVG): {plot_avg}')\n", + " print(f'>> MIN(MAX): {plot_max}')\n", + " elif c == 'MAX':\n", + " plot_df = date_df.iloc[:,2]\n", + " plot_avg = plot_df.mean()\n", + " plot_min = plot_df.min()\n", + " plot_max = plot_df.max()\n", + " print(f'>> MAX(MIN): {plot_min}')\n", + " print(f'>> MAX(AVG): {plot_avg}')\n", + " print(f'>> MAX(MAX): {plot_max}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31923da3", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/etc/Hamon_EDA_ver2.ipynb b/etc/Hamon_EDA_ver2.ipynb new file mode 100644 index 0000000..fcc0099 --- /dev/null +++ b/etc/Hamon_EDA_ver2.ipynb @@ -0,0 +1,2562 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "hHGnodIzL8ux", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hHGnodIzL8ux", + "outputId": "845d8e3b-d218-48c9-def2-50578ea340bf" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mounted at /gdrive\n" + ] + } + ], + "source": [ + "from google.colab import drive\n", + "drive.mount('/gdrive')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "617dbb54", + "metadata": { + "id": "617dbb54" + }, + "outputs": [], + "source": [ + "import os\n", + "import pandas as pd\n", + "import glob" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "69d77230", + "metadata": { + "id": "69d77230" + }, + "outputs": [], + "source": [ + "df = pd.read_csv('/gdrive/MyDrive/Colab Notebooks/total_df.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "31cb8a56", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "31cb8a56", + "outputId": "4c439845-84ab-40a8-a1b0-f6a181eeeb25" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['YYYYMMDD', 'HHMMSS', 'MNG_NO', 'IF_IDX', 'AVG_INBPS', 'MIN_INBPS',\n", + " 'MAX_INBPS', 'AVG_OUTBPS', 'MIN_OUTBPS', 'MAX_OUTBPS', 'AVG_INPPS',\n", + " 'MIN_INPPS', 'MAX_INPPS', 'AVG_OUTPPS', 'MIN_OUTPPS', 'MAX_OUTPPS',\n", + " 'AVG_INERR', 'MIN_INERR', 'MAX_INERR', 'AVG_OUTERR', 'MIN_OUTERR',\n", + " 'MAX_OUTERR', 'AVG_CRC', 'MIN_CRC', 'MAX_CRC', 'AVG_COLLISION',\n", + " 'MIN_COLLISION', 'MAX_COLLISION', 'AVG_INDROP', 'MIN_INDROP',\n", + " 'MAX_INDROP', 'AVG_OUTDROP', 'MIN_OUTDROP', 'MAX_OUTDROP',\n", + " 'AVG_INNUPPS', 'MIN_INNUPPS', 'MAX_INNUPPS', 'AVG_OUTNUPPS',\n", + " 'MIN_OUTNUPPS', 'MAX_OUTNUPPS', 'AVG_INDISCARD', 'MIN_INDISCARD',\n", + " 'MAX_INDISCARD', 'AVG_OUTDISCARD', 'MIN_OUTDISCARD', 'MAX_OUTDISCARD',\n", + " 'AVG_INMCASTPPS', 'MIN_INMCASTPPS', 'MAX_INMCASTPPS', 'AVG_OUTMCASTPPS',\n", + " 'MIN_OUTMCASTPPS', 'MAX_OUTMCASTPPS', 'AVG_INBCASTPPS',\n", + " 'MIN_INBCASTPPS', 'MAX_INBCASTPPS', 'AVG_OUTBCASTPPS',\n", + " 'MIN_OUTBCASTPPS', 'MAX_OUTBCASTPPS'],\n", + " dtype='object')" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "3a4033a2", + "metadata": { + "id": "3a4033a2" + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1c98808a", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1c98808a", + "outputId": "821e069f-6ca8-41fb-fa25-f6c78b3f2bda" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "YYYYMMDD : 7\n", + "HHMMSS : 288\n", + "MNG_NO : 10686\n", + "IF_IDX : 26\n", + "AVG_INBPS : 4413650\n", + "MIN_INBPS : 4413650\n", + "MAX_INBPS : 4413650\n", + "AVG_OUTBPS : 1567959\n", + "MIN_OUTBPS : 1567959\n", + "MAX_OUTBPS : 1567959\n", + "AVG_INPPS : 44142\n", + "MIN_INPPS : 44142\n", + "MAX_INPPS : 44142\n", + "AVG_OUTPPS : 287257\n", + "MIN_OUTPPS : 287257\n", + "MAX_OUTPPS : 287257\n", + "AVG_INERR : 1302\n", + "MIN_INERR : 1302\n", + "MAX_INERR : 1302\n", + "AVG_OUTERR : 1065\n", + "MIN_OUTERR : 1065\n", + "MAX_OUTERR : 1065\n", + "AVG_CRC : 1\n", + "MIN_CRC : 1\n", + "MAX_CRC : 1\n", + "AVG_COLLISION : 1\n", + "MIN_COLLISION : 1\n", + "MAX_COLLISION : 1\n", + "AVG_INDROP : 1\n", + "MIN_INDROP : 1\n", + "MAX_INDROP : 1\n", + "AVG_OUTDROP : 1\n", + "MIN_OUTDROP : 1\n", + "MAX_OUTDROP : 1\n", + "AVG_INNUPPS : 897\n", + "MIN_INNUPPS : 897\n", + "MAX_INNUPPS : 897\n", + "AVG_OUTNUPPS : 287257\n", + "MIN_OUTNUPPS : 287257\n", + "MAX_OUTNUPPS : 287257\n", + "AVG_INDISCARD : 28382\n", + "MIN_INDISCARD : 28382\n", + "MAX_INDISCARD : 28382\n", + "AVG_OUTDISCARD : 709\n", + "MIN_OUTDISCARD : 709\n", + "MAX_OUTDISCARD : 709\n", + "AVG_INMCASTPPS : 1\n", + "MIN_INMCASTPPS : 1\n", + "MAX_INMCASTPPS : 1\n", + "AVG_OUTMCASTPPS : 1\n", + "MIN_OUTMCASTPPS : 1\n", + "MAX_OUTMCASTPPS : 1\n", + "AVG_INBCASTPPS : 1\n", + "MIN_INBCASTPPS : 1\n", + "MAX_INBCASTPPS : 1\n", + "AVG_OUTBCASTPPS : 1\n", + "MIN_OUTBCASTPPS : 1\n", + "MAX_OUTBCASTPPS : 1\n" + ] + } + ], + "source": [ + "for col in df.columns:\n", + " print(f'{col} : {len(df[col].unique())}')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "d8ad2720", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "d8ad2720", + "outputId": "bfef1b51-f0f1-4b0c-dbc4-3a45c36c8efd" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(23195128, 58)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "43e80a22", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 226 + }, + "id": "43e80a22", + "outputId": "8ff31d12-e303-4c63-bbcc-2df2dad55c02" + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YYYYMMDDHHMMSSMNG_NOIF_IDXAVG_INBPSMIN_INBPSMAX_INBPSAVG_OUTBPSMIN_OUTBPSMAX_OUTBPSAVG_INPPSMIN_INPPSMAX_INPPSAVG_OUTPPSMIN_OUTPPSMAX_OUTPPSAVG_INERRMIN_INERRMAX_INERRAVG_OUTERRMIN_OUTERRMAX_OUTERRAVG_CRCMIN_CRCMAX_CRCAVG_COLLISIONMIN_COLLISIONMAX_COLLISIONAVG_INDROPMIN_INDROPMAX_INDROPAVG_OUTDROPMIN_OUTDROPMAX_OUTDROPAVG_INNUPPSMIN_INNUPPSMAX_INNUPPSAVG_OUTNUPPSMIN_OUTNUPPSMAX_OUTNUPPSAVG_INDISCARDMIN_INDISCARDMAX_INDISCARDAVG_OUTDISCARDMIN_OUTDISCARDMAX_OUTDISCARDAVG_INMCASTPPSMIN_INMCASTPPSMAX_INMCASTPPSAVG_OUTMCASTPPSMIN_OUTMCASTPPSMAX_OUTMCASTPPSAVG_INBCASTPPSMIN_INBCASTPPSMAX_INBCASTPPSAVG_OUTBCASTPPSMIN_OUTBCASTPPSMAX_OUTBCASTPPS
02021062023550026641124669926699266992365763657636576222222457245724572000000000000000000000457245724572000000000000000000
1202106208550055052378243782437824361923619236192101010141414000000000000000000000141414000000000000000000
2202106208500055052879287928792281042810428104555101010000000000000000000000101010000000000000000000
3202106208450055052144336144336144336436804368043680202020161616000000000000000000000161616000000000000000000
4202106208400055052456564565645656507205072050720111111161616000000000000000000000161616000000000000000000
\n", + "
" + ], + "text/plain": [ + " YYYYMMDD HHMMSS MNG_NO ... AVG_OUTBCASTPPS MIN_OUTBCASTPPS MAX_OUTBCASTPPS\n", + "0 20210620 235500 26641 ... 0 0 0\n", + "1 20210620 85500 5505 ... 0 0 0\n", + "2 20210620 85000 5505 ... 0 0 0\n", + "3 20210620 84500 5505 ... 0 0 0\n", + "4 20210620 84000 5505 ... 0 0 0\n", + "\n", + "[5 rows x 58 columns]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "a5dfd123", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 226 + }, + "id": "a5dfd123", + "outputId": "9ebee84f-588a-45fb-ce00-cb830ad567ab" + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YYYYMMDDHHMMSSMNG_NOIF_IDXAVG_INBPSMIN_INBPSMAX_INBPSAVG_OUTBPSMIN_OUTBPSMAX_OUTBPSAVG_INPPSMIN_INPPSMAX_INPPSAVG_OUTPPSMIN_OUTPPSMAX_OUTPPSAVG_INERRMIN_INERRMAX_INERRAVG_OUTERRMIN_OUTERRMAX_OUTERRAVG_CRCMIN_CRCMAX_CRCAVG_COLLISIONMIN_COLLISIONMAX_COLLISIONAVG_INDROPMIN_INDROPMAX_INDROPAVG_OUTDROPMIN_OUTDROPMAX_OUTDROPAVG_INNUPPSMIN_INNUPPSMAX_INNUPPSAVG_OUTNUPPSMIN_OUTNUPPSMAX_OUTNUPPSAVG_INDISCARDMIN_INDISCARDMAX_INDISCARDAVG_OUTDISCARDMIN_OUTDISCARDMAX_OUTDISCARDAVG_INMCASTPPSMIN_INMCASTPPSMAX_INMCASTPPSAVG_OUTMCASTPPSMIN_OUTMCASTPPSMAX_OUTMCASTPPSAVG_INBCASTPPSMIN_INBCASTPPSMAX_INBCASTPPSAVG_OUTBCASTPPSMIN_OUTBCASTPPSMAX_OUTBCASTPPS
23195123202106261505002069511161956016195601619560279856279856279856164164164727272000000000000000000000727272000000000000000000
23195124202106261505002069411133448133448133448167521675216752141414111111000000000000000000000111111000000000000000000
23195125202106261505002069311151124815112481511248381443814438144131131131272727000000000000000000000272727000000000000000000
2319512620210626150500221012438244382443824727047270472704171717212121000000000000000000000212121000000000000000000
2319512720210626500154212558005580055800694646946469464222222282828000000000000000000000282828000000000000000000
\n", + "
" + ], + "text/plain": [ + " YYYYMMDD HHMMSS ... MIN_OUTBCASTPPS MAX_OUTBCASTPPS\n", + "23195123 20210626 150500 ... 0 0\n", + "23195124 20210626 150500 ... 0 0\n", + "23195125 20210626 150500 ... 0 0\n", + "23195126 20210626 150500 ... 0 0\n", + "23195127 20210626 500 ... 0 0\n", + "\n", + "[5 rows x 58 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.tail()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "e481efa2", + "metadata": { + "id": "e481efa2" + }, + "outputs": [], + "source": [ + "import matplotlib as mpl\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7575efab", + "metadata": { + "id": "7575efab" + }, + "outputs": [], + "source": [ + "from collections import Counter" + ] + }, + { + "cell_type": "markdown", + "id": "4835a31d", + "metadata": { + "id": "4835a31d" + }, + "source": [ + "## Get Count for Each Date" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "64e8097f", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "64e8097f", + "outputId": "88679368-aa47-4b16-a4d3-e45d42bdcfd6" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['INBPS',\n", + " 'OUTBPS',\n", + " 'INDISCARD',\n", + " 'OUTDISCARD',\n", + " 'INERR',\n", + " 'OUTERR',\n", + " 'INNUPPS',\n", + " 'OUTNUPPS',\n", + " 'INPPS',\n", + " 'OUTPPS']" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "check_cols = ['INBPS', 'OUTBPS', \n", + " 'INDISCARD', 'OUTDISCARD', \n", + " 'INERR', 'OUTERR', \n", + " 'INNUPPS', 'OUTNUPPS', \n", + " 'INPPS', 'OUTPPS']\n", + "\n", + "check_cols" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "3-tUOC-9QhX3", + "metadata": { + "id": "3-tUOC-9QhX3" + }, + "outputs": [], + "source": [ + "INBPS_COLS = []\n", + "OUTBPS_COLS = []\n", + "INDISCARD_COLS = []\n", + "OUTDISCARD_COLS = []\n", + "INERR_COLS = []\n", + "OUTERR_COLS = []\n", + "INNUPPS_COLS = []\n", + "OUTNUPPS_COLS = []\n", + "INPPS_COLS = []\n", + "OUTPPS_COLS = []" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ajyJGDwoRF55", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 36 + }, + "id": "ajyJGDwoRF55", + "outputId": "813ebc95-51b0-44f6-9acf-d99de420dbb5" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'AVG_INBPS'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cols = 'INBPS'\n", + "'AVG_' + cols" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "ACq16XK6Qzzf", + "metadata": { + "id": "ACq16XK6Qzzf" + }, + "outputs": [], + "source": [ + "for cols in check_cols:\n", + " if cols == 'INBPS':\n", + " INBPS_COLS.append('MIN_'+cols)\n", + " INBPS_COLS.append('MAX_'+cols)\n", + " INBPS_COLS.append('AVG_'+cols)\n", + " elif cols == 'OUTBPS':\n", + " OUTBPS_COLS.append('MIN_'+cols)\n", + " OUTBPS_COLS.append('MAX_'+cols)\n", + " OUTBPS_COLS.append('AVG_'+cols)\n", + " elif cols == 'INDISCARD':\n", + " INDISCARD_COLS.append('MIN_'+cols)\n", + " INDISCARD_COLS.append('MAX_'+cols)\n", + " INDISCARD_COLS.append('AVG_'+cols)\n", + " elif cols == 'OUTDISCARD':\n", + " OUTDISCARD_COLS.append('MIN_'+cols)\n", + " OUTDISCARD_COLS.append('MAX_'+cols)\n", + " OUTDISCARD_COLS.append('AVG_'+cols)\n", + " elif cols == 'INERR':\n", + " INERR_COLS.append('MIN_'+cols)\n", + " INERR_COLS.append('MAX_'+cols)\n", + " INERR_COLS.append('AVG_'+cols)\n", + " elif cols == 'OUTERR':\n", + " OUTERR_COLS.append('MIN_'+cols)\n", + " OUTERR_COLS.append('MAX_'+cols)\n", + " OUTERR_COLS.append('AVG_'+cols)\n", + " elif cols == 'INNUPPS':\n", + " INNUPPS_COLS.append('MIN_'+cols)\n", + " INNUPPS_COLS.append('MAX_'+cols)\n", + " INNUPPS_COLS.append('AVG_'+cols)\n", + " elif cols == 'OUTNUPPS':\n", + " OUTNUPPS_COLS.append('MIN_'+cols)\n", + " OUTNUPPS_COLS.append('MAX_'+cols)\n", + " OUTNUPPS_COLS.append('AVG_'+cols)\n", + " elif cols == 'INPPS':\n", + " INPPS_COLS.append('MIN_'+cols)\n", + " INPPS_COLS.append('MAX_'+cols)\n", + " INPPS_COLS.append('AVG_'+cols)\n", + " elif cols == 'OUTPPS':\n", + " OUTPPS_COLS.append('MIN_'+cols)\n", + " OUTPPS_COLS.append('MAX_'+cols)\n", + " OUTPPS_COLS.append('AVG_'+cols)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "kj_9zpV3Sj49", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "kj_9zpV3Sj49", + "outputId": "aeb0159e-eca3-4774-a411-0841611afd9b" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['MIN_INBPS', 'MAX_INBPS', 'AVG_INBPS']" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "INBPS_COLS" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "LhJBPHNFSo7Q", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "LhJBPHNFSo7Q", + "outputId": "ff52f4db-a1be-4189-c004-c90bea14af56" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[['MIN_INBPS', 'MAX_INBPS', 'AVG_INBPS'],\n", + " ['MIN_OUTBPS', 'MAX_OUTBPS', 'AVG_OUTBPS'],\n", + " ['MIN_INDISCARD', 'MAX_INDISCARD', 'AVG_INDISCARD'],\n", + " ['MIN_OUTDISCARD', 'MAX_OUTDISCARD', 'AVG_OUTDISCARD'],\n", + " ['MIN_INERR', 'MAX_INERR', 'AVG_INERR'],\n", + " ['MIN_OUTERR', 'MAX_OUTERR', 'AVG_OUTERR'],\n", + " ['MIN_INNUPPS', 'MAX_INNUPPS', 'AVG_INNUPPS'],\n", + " ['MIN_OUTNUPPS', 'MAX_OUTNUPPS', 'AVG_OUTNUPPS'],\n", + " ['MIN_INPPS', 'MAX_INPPS', 'AVG_INPPS'],\n", + " ['MIN_OUTPPS', 'MAX_OUTPPS', 'AVG_OUTPPS']]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "COLS = [INBPS_COLS, OUTBPS_COLS, \n", + " INDISCARD_COLS, OUTDISCARD_COLS, \n", + " INERR_COLS, OUTERR_COLS, \n", + " INNUPPS_COLS, OUTNUPPS_COLS, \n", + " INPPS_COLS, OUTPPS_COLS]\n", + "\n", + "COLS" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "2d0de5f3", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "2d0de5f3", + "outputId": "8e14e897-9b33-483b-8f93-a95c5fa13efc" + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YYYYMMDD
020210620
120210620
220210620
320210620
420210620
\n", + "
" + ], + "text/plain": [ + " YYYYMMDD\n", + "0 20210620\n", + "1 20210620\n", + "2 20210620\n", + "3 20210620\n", + "4 20210620" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dates_df = pd.DataFrame(df['YYYYMMDD'])\n", + "dates_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "5a96b6fa", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 424 + }, + "id": "5a96b6fa", + "outputId": "6545e16c-31ac-4233-c536-8e37f133fa89" + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
YYYYMMDDMIN_INBPSMAX_INBPSAVG_INBPS
020210620669926699266992
120210620378243782437824
220210620879287928792
320210620144336144336144336
420210620456564565645656
...............
2319512320210626161956016195601619560
2319512420210626133448133448133448
2319512520210626151124815112481511248
2319512620210626438244382443824
2319512720210626558005580055800
\n", + "

23195128 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " YYYYMMDD MIN_INBPS MAX_INBPS AVG_INBPS\n", + "0 20210620 66992 66992 66992\n", + "1 20210620 37824 37824 37824\n", + "2 20210620 8792 8792 8792\n", + "3 20210620 144336 144336 144336\n", + "4 20210620 45656 45656 45656\n", + "... ... ... ... ...\n", + "23195123 20210626 1619560 1619560 1619560\n", + "23195124 20210626 133448 133448 133448\n", + "23195125 20210626 1511248 1511248 1511248\n", + "23195126 20210626 43824 43824 43824\n", + "23195127 20210626 55800 55800 55800\n", + "\n", + "[23195128 rows x 4 columns]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[['YYYYMMDD','MIN_INBPS', 'MAX_INBPS', 'AVG_INBPS']]#.iloc[:,1:]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "4fF3zaFJeJyZ", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "4fF3zaFJeJyZ", + "outputId": "ebb0c6fa-cbc6-4088-945d-0e7cc5e517dc" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[20210620, 20210621, 20210622, 20210623, 20210624, 20210625, 20210626]" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dates = list(df['YYYYMMDD'].unique())\n", + "dates" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "ZGaB7FIuV6AL", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ZGaB7FIuV6AL", + "outputId": "c86e9e93-233b-4d72-b8c4-ef9c64d46948" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['MIN_INBPS', 'MAX_INBPS', 'AVG_INBPS']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_OUTBPS', 'MAX_OUTBPS', 'AVG_OUTBPS']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_INDISCARD', 'MAX_INDISCARD', 'AVG_INDISCARD']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_OUTDISCARD', 'MAX_OUTDISCARD', 'AVG_OUTDISCARD']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_INERR', 'MAX_INERR', 'AVG_INERR']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_OUTERR', 'MAX_OUTERR', 'AVG_OUTERR']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_INNUPPS', 'MAX_INNUPPS', 'AVG_INNUPPS']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_OUTNUPPS', 'MAX_OUTNUPPS', 'AVG_OUTNUPPS']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_INPPS', 'MAX_INPPS', 'AVG_INPPS']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n", + "['MIN_OUTPPS', 'MAX_OUTPPS', 'AVG_OUTPPS']\n", + "Comparing MIN and MAX : [ True]\n", + "Comparing MIN and AVG : [ True]\n", + "Comparing MAX and AVG : [ True]\n", + "------end------\n" + ] + } + ], + "source": [ + "#['MIN_INBPS', 'MAX_INBPS', 'AVG_INBPS']\n", + "\n", + "for COL in COLS:\n", + " print(COL)\n", + " print(f'Comparing MIN and MAX : {pd.Series(df[COL[0]]==df[COL[1]]).unique()}')\n", + " print(f'Comparing MIN and AVG : {pd.Series(df[COL[0]]==df[COL[2]]).unique()}')\n", + " print(f'Comparing MAX and AVG : {pd.Series(df[COL[1]]==df[COL[2]]).unique()}')\n", + " print('------end------')" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "2qezVIagVlkd", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2qezVIagVlkd", + "outputId": "43cf2793-1f51-42f9-e84a-1ccce0cb73c6" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ True])" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.Series(df['MIN_INBPS']==df['MAX_INBPS']).unique()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "BcrUXWcsTrYe", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "BcrUXWcsTrYe", + "outputId": "eacb6528-6066-4388-862b-8a7c71f0cb87" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['MIN_INBPS', 'MAX_INBPS', 'AVG_INBPS']\n", + " YYYYMMDD MIN_INBPS MAX_INBPS AVG_INBPS\n", + "0 20210620 66992 66992 66992\n", + "1 20210620 37824 37824 37824\n", + "2 20210620 8792 8792 8792\n", + "3 20210620 144336 144336 144336\n", + "4 20210620 45656 45656 45656\n", + " YYYYMMDD MIN_INBPS MAX_INBPS AVG_INBPS\n", + "23195123 20210626 1619560 1619560 1619560\n", + "23195124 20210626 133448 133448 133448\n", + "23195125 20210626 1511248 1511248 1511248\n", + "23195126 20210626 43824 43824 43824\n", + "23195127 20210626 55800 55800 55800\n", + "------end------\n", + "['MIN_OUTBPS', 'MAX_OUTBPS', 'AVG_OUTBPS']\n", + " YYYYMMDD MIN_OUTBPS MAX_OUTBPS AVG_OUTBPS\n", + "0 20210620 36576 36576 36576\n", + "1 20210620 36192 36192 36192\n", + "2 20210620 28104 28104 28104\n", + "3 20210620 43680 43680 43680\n", + "4 20210620 50720 50720 50720\n", + " YYYYMMDD MIN_OUTBPS MAX_OUTBPS AVG_OUTBPS\n", + "23195123 20210626 279856 279856 279856\n", + "23195124 20210626 16752 16752 16752\n", + "23195125 20210626 38144 38144 38144\n", + "23195126 20210626 72704 72704 72704\n", + "23195127 20210626 69464 69464 69464\n", + "------end------\n", + "['MIN_INDISCARD', 'MAX_INDISCARD', 'AVG_INDISCARD']\n", + " YYYYMMDD MIN_INDISCARD MAX_INDISCARD AVG_INDISCARD\n", + "0 20210620 0 0 0\n", + "1 20210620 0 0 0\n", + "2 20210620 0 0 0\n", + "3 20210620 0 0 0\n", + "4 20210620 0 0 0\n", + " YYYYMMDD MIN_INDISCARD MAX_INDISCARD AVG_INDISCARD\n", + "23195123 20210626 0 0 0\n", + "23195124 20210626 0 0 0\n", + "23195125 20210626 0 0 0\n", + "23195126 20210626 0 0 0\n", + "23195127 20210626 0 0 0\n", + "------end------\n", + "['MIN_OUTDISCARD', 'MAX_OUTDISCARD', 'AVG_OUTDISCARD']\n", + " YYYYMMDD MIN_OUTDISCARD MAX_OUTDISCARD AVG_OUTDISCARD\n", + "0 20210620 0 0 0\n", + "1 20210620 0 0 0\n", + "2 20210620 0 0 0\n", + "3 20210620 0 0 0\n", + "4 20210620 0 0 0\n", + " YYYYMMDD MIN_OUTDISCARD MAX_OUTDISCARD AVG_OUTDISCARD\n", + "23195123 20210626 0 0 0\n", + "23195124 20210626 0 0 0\n", + "23195125 20210626 0 0 0\n", + "23195126 20210626 0 0 0\n", + "23195127 20210626 0 0 0\n", + "------end------\n", + "['MIN_INERR', 'MAX_INERR', 'AVG_INERR']\n", + " YYYYMMDD MIN_INERR MAX_INERR AVG_INERR\n", + "0 20210620 0 0 0\n", + "1 20210620 0 0 0\n", + "2 20210620 0 0 0\n", + "3 20210620 0 0 0\n", + "4 20210620 0 0 0\n", + " YYYYMMDD MIN_INERR MAX_INERR AVG_INERR\n", + "23195123 20210626 0 0 0\n", + "23195124 20210626 0 0 0\n", + "23195125 20210626 0 0 0\n", + "23195126 20210626 0 0 0\n", + "23195127 20210626 0 0 0\n", + "------end------\n", + "['MIN_OUTERR', 'MAX_OUTERR', 'AVG_OUTERR']\n", + " YYYYMMDD MIN_OUTERR MAX_OUTERR AVG_OUTERR\n", + "0 20210620 0 0 0\n", + "1 20210620 0 0 0\n", + "2 20210620 0 0 0\n", + "3 20210620 0 0 0\n", + "4 20210620 0 0 0\n", + " YYYYMMDD MIN_OUTERR MAX_OUTERR AVG_OUTERR\n", + "23195123 20210626 0 0 0\n", + "23195124 20210626 0 0 0\n", + "23195125 20210626 0 0 0\n", + "23195126 20210626 0 0 0\n", + "23195127 20210626 0 0 0\n", + "------end------\n", + "['MIN_INNUPPS', 'MAX_INNUPPS', 'AVG_INNUPPS']\n", + " YYYYMMDD MIN_INNUPPS MAX_INNUPPS AVG_INNUPPS\n", + "0 20210620 0 0 0\n", + "1 20210620 0 0 0\n", + "2 20210620 0 0 0\n", + "3 20210620 0 0 0\n", + "4 20210620 0 0 0\n", + " YYYYMMDD MIN_INNUPPS MAX_INNUPPS AVG_INNUPPS\n", + "23195123 20210626 0 0 0\n", + "23195124 20210626 0 0 0\n", + "23195125 20210626 0 0 0\n", + "23195126 20210626 0 0 0\n", + "23195127 20210626 0 0 0\n", + "------end------\n", + "['MIN_OUTNUPPS', 'MAX_OUTNUPPS', 'AVG_OUTNUPPS']\n", + " YYYYMMDD MIN_OUTNUPPS MAX_OUTNUPPS AVG_OUTNUPPS\n", + "0 20210620 4572 4572 4572\n", + "1 20210620 14 14 14\n", + "2 20210620 10 10 10\n", + "3 20210620 16 16 16\n", + "4 20210620 16 16 16\n", + " YYYYMMDD MIN_OUTNUPPS MAX_OUTNUPPS AVG_OUTNUPPS\n", + "23195123 20210626 72 72 72\n", + "23195124 20210626 11 11 11\n", + "23195125 20210626 27 27 27\n", + "23195126 20210626 21 21 21\n", + "23195127 20210626 28 28 28\n", + "------end------\n", + "['MIN_INPPS', 'MAX_INPPS', 'AVG_INPPS']\n", + " YYYYMMDD MIN_INPPS MAX_INPPS AVG_INPPS\n", + "0 20210620 22 22 22\n", + "1 20210620 10 10 10\n", + "2 20210620 5 5 5\n", + "3 20210620 20 20 20\n", + "4 20210620 11 11 11\n", + " YYYYMMDD MIN_INPPS MAX_INPPS AVG_INPPS\n", + "23195123 20210626 164 164 164\n", + "23195124 20210626 14 14 14\n", + "23195125 20210626 131 131 131\n", + "23195126 20210626 17 17 17\n", + "23195127 20210626 22 22 22\n", + "------end------\n", + "['MIN_OUTPPS', 'MAX_OUTPPS', 'AVG_OUTPPS']\n", + " YYYYMMDD MIN_OUTPPS MAX_OUTPPS AVG_OUTPPS\n", + "0 20210620 4572 4572 4572\n", + "1 20210620 14 14 14\n", + "2 20210620 10 10 10\n", + "3 20210620 16 16 16\n", + "4 20210620 16 16 16\n", + " YYYYMMDD MIN_OUTPPS MAX_OUTPPS AVG_OUTPPS\n", + "23195123 20210626 72 72 72\n", + "23195124 20210626 11 11 11\n", + "23195125 20210626 27 27 27\n", + "23195126 20210626 21 21 21\n", + "23195127 20210626 28 28 28\n", + "------end------\n" + ] + } + ], + "source": [ + "for COL in COLS:\n", + " print(COL)\n", + " print(df[['YYYYMMDD']+COL].head())\n", + " print(df[['YYYYMMDD']+COL].tail())\n", + " print('------end------')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "yiYfd3poUX1Y", + "metadata": { + "id": "yiYfd3poUX1Y" + }, + "outputs": [], + "source": [ + "for COL in COLS:\n", + " print(COL)\n", + " print(df[['YYYYMMDD']+COL].head())\n", + " print(df[['YYYYMMDD']+COL].tail())\n", + " print('------end------')" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "15a93a5d", + "metadata": { + "id": "15a93a5d" + }, + "outputs": [], + "source": [ + "vis_cols = ['AVG_INERR', 'AVG_INBPS', 'AVG_INDISCARD', 'AVG_INNUPPS', 'AVG_INPPS', \n", + " 'AVG_OUTERR', 'AVG_OUTBPS', 'AVG_OUTDISCARD', 'AVG_OUTNUPPS', 'AVG_OUTPPS']" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "sFFZxrFqfc82", + "metadata": { + "id": "sFFZxrFqfc82" + }, + "outputs": [], + "source": [ + "save_path = '/gdrive/MyDrive/Colab Notebooks/results/'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9q7_SdSEevGA", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "9q7_SdSEevGA", + "outputId": "ebd6a4c7-6a81-4950-858c-19393a486c32" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "AVG INERR\n", + "AVG INBPS\n", + "AVG INDISCARD\n", + "AVG INNUPPS\n", + "AVG INPPS\n", + "AVG OUTERR\n", + "AVG OUTBPS\n", + "AVG OUTDISCARD\n", + "AVG OUTNUPPS\n", + "AVG OUTPPS\n" + ] + } + ], + "source": [ + "for col in vis_cols:\n", + " stat, _, name = col.partition(\"_\")\n", + " print(stat, name)\n", + "\n", + " # define plot_df\n", + " plot_df = df[col]\n", + "\n", + " # define fig\n", + " fig = plt.figure()\n", + "\n", + " plot_df.plot(figsize = (12, 6))\n", + "\n", + " plt.title(f'{name}')\n", + "\n", + " plt.savefig(save_path+f\"{name}_plot.png\", dpi=200)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "078c6ecb", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 449 + }, + "id": "078c6ecb", + "outputId": "979574a9-6f91-46aa-fe69-0ab5e8c3badd", + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "vis_col: INERR\n", + ">>> plotting 20210620\n" + ] + }, + { + "ename": "IndexError", + "evalue": "ignored", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0mplot_df\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdate_df\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0miloc\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mc\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'MAX'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 33\u001b[0;31m \u001b[0mplot_df\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdate_df\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0miloc\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 34\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;31m# define fig\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 871\u001b[0m \u001b[0;31m# AttributeError for IntervalTree get_value\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 872\u001b[0m \u001b[0;32mpass\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 873\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_tuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 874\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 875\u001b[0m \u001b[0;31m# we by definition only have the 0th axis\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py\u001b[0m in \u001b[0;36m_getitem_tuple\u001b[0;34m(self, tup)\u001b[0m\n\u001b[1;32m 1441\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_getitem_tuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtup\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mTuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1442\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1443\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_has_valid_tuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtup\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1444\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1445\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_lowerdim\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtup\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py\u001b[0m in \u001b[0;36m_has_valid_tuple\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 700\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mIndexingError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Too many indexers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 701\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 702\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_validate_key\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mk\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 703\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mValueError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 704\u001b[0m raise ValueError(\n", + "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py\u001b[0m in \u001b[0;36m_validate_key\u001b[0;34m(self, key, axis)\u001b[0m\n\u001b[1;32m 1350\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1351\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1352\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_validate_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1353\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1354\u001b[0m \u001b[0;31m# a tuple should already have been caught by this point\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py\u001b[0m in \u001b[0;36m_validate_integer\u001b[0;34m(self, key, axis)\u001b[0m\n\u001b[1;32m 1435\u001b[0m \u001b[0mlen_axis\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mobj\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_axis\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0maxis\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1436\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mkey\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0mlen_axis\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mkey\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0mlen_axis\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1437\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mIndexError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"single positional indexer is out-of-bounds\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1438\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1439\u001b[0m \u001b[0;31m# -------------------------------------------------------------------\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mIndexError\u001b[0m: single positional indexer is out-of-bounds" + ] + } + ], + "source": [ + "for vis_col in vis_cols:\n", + " print(f'vis_col: {vis_col}')\n", + " tmp_cols = []\n", + " \n", + " for col in cols:\n", + " #print(f'>>>>>col: {col}')\n", + " if vis_col in col:\n", + " tmp_cols.append(col)\n", + " \n", + " #print(tmp_cols)\n", + " #print('--------------------')\n", + " tmp_df = df[tmp_cols]\n", + " \n", + " # make tmp dataframe\n", + " tmp_df = pd.concat([dates_df, tmp_df], axis = 1)\n", + " \n", + " # for dates\n", + " for date in dates:\n", + " print(f'>>> plotting {date}')\n", + " \n", + " # use data at certain date\n", + " date_df = tmp_df[tmp_df['YYYYMMDD']==date].iloc[:,1:]\n", + " \n", + " criteria = ['MAX', 'MIN', 'AVG']\n", + " \n", + " for c in criteria:\n", + " \n", + " if c == 'AVG':\n", + " plot_df = date_df.iloc[:,0]\n", + " elif c == 'MIN':\n", + " plot_df = date_df.iloc[:,1]\n", + " elif c == 'MAX':\n", + " plot_df = date_df.iloc[:,2]\n", + " \n", + " # define fig\n", + " fig = plt.figure()\n", + "\n", + " plot_df.plot(figsize = (12, 6))\n", + "\n", + " plt.title(f'{c}_{vis_col}({date}) ')\n", + "\n", + " plt.savefig(save_path+ f\"/{c}_{vis_col}_{date}.png\", dpi=200)\n", + " \n", + " plt.close('all')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee353892", + "metadata": { + "id": "ee353892", + "outputId": "f6998abb-c304-439e-a2a0-b4973b1602a4", + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "vis_col: INERR\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0009929763219236904\n", + ">> MAX(MAX): 103\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0009929763219236904\n", + ">> MIN(MAX): 103\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0009929763219236904\n", + ">> AVG(MAX): 103\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.1070327038198467\n", + ">> MAX(MAX): 9360\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.1070327038198467\n", + ">> MIN(MAX): 9360\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.1070327038198467\n", + ">> AVG(MAX): 9360\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.21545382251356252\n", + ">> MAX(MAX): 12166\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.21545382251356252\n", + ">> MIN(MAX): 12166\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.21545382251356252\n", + ">> AVG(MAX): 12166\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.1899605151255562\n", + ">> MAX(MAX): 20995\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.1899605151255562\n", + ">> MIN(MAX): 20995\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.1899605151255562\n", + ">> AVG(MAX): 20995\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.3504950319532711\n", + ">> MAX(MAX): 87505\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.3504950319532711\n", + ">> MIN(MAX): 87505\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.3504950319532711\n", + ">> AVG(MAX): 87505\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.09246079843196818\n", + ">> MAX(MAX): 16707\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.09246079843196818\n", + ">> MIN(MAX): 16707\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.09246079843196818\n", + ">> AVG(MAX): 16707\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.013125300391402939\n", + ">> MAX(MAX): 3539\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.013125300391402939\n", + ">> MIN(MAX): 3539\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.013125300391402939\n", + ">> AVG(MAX): 3539\n", + "vis_col: OUTDROP\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "vis_col: INNUPPS\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.4232476784349255\n", + ">> MAX(MAX): 230423\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.4232476784349255\n", + ">> MIN(MAX): 230423\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.4232476784349255\n", + ">> AVG(MAX): 230423\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.3255765156290704\n", + ">> MAX(MAX): 4693\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.3255765156290704\n", + ">> MIN(MAX): 4693\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.3255765156290704\n", + ">> AVG(MAX): 4693\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.300698597051876\n", + ">> MAX(MAX): 3564\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.300698597051876\n", + ">> MIN(MAX): 3564\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.300698597051876\n", + ">> AVG(MAX): 3564\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.3138820131438875\n", + ">> MAX(MAX): 6472\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.3138820131438875\n", + ">> MIN(MAX): 6472\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.3138820131438875\n", + ">> AVG(MAX): 6472\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.414565846192937\n", + ">> MAX(MAX): 8387\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.414565846192937\n", + ">> MIN(MAX): 8387\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.414565846192937\n", + ">> AVG(MAX): 8387\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.3606745082676048\n", + ">> MAX(MAX): 3692\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.3606745082676048\n", + ">> MIN(MAX): 3692\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.3606745082676048\n", + ">> AVG(MAX): 3692\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 1.4019500500077176\n", + ">> MAX(MAX): 4121\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 1.4019500500077176\n", + ">> MIN(MAX): 4121\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 1.4019500500077176\n", + ">> AVG(MAX): 4121\n", + "vis_col: OUTNUPPS\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 2065.437395895265\n", + ">> MAX(MAX): 33784710\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 2065.437395895265\n", + ">> MIN(MAX): 33784710\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 2065.437395895265\n", + ">> AVG(MAX): 33784710\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 10884.217727320281\n", + ">> MAX(MAX): 45275418\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 10884.217727320281\n", + ">> MIN(MAX): 45275418\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 10884.217727320281\n", + ">> AVG(MAX): 45275418\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 10274.470403238776\n", + ">> MAX(MAX): 34360111\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 10274.470403238776\n", + ">> MIN(MAX): 34360111\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 10274.470403238776\n", + ">> AVG(MAX): 34360111\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 10379.628168063316\n", + ">> MAX(MAX): 49227501\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 10379.628168063316\n", + ">> MIN(MAX): 49227501\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 10379.628168063316\n", + ">> AVG(MAX): 49227501\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 10318.102998850687\n", + ">> MAX(MAX): 46340093\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 10318.102998850687\n", + ">> MIN(MAX): 46340093\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 10318.102998850687\n", + ">> AVG(MAX): 46340093\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 9422.836515565848\n", + ">> MAX(MAX): 32470807\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 9422.836515565848\n", + ">> MIN(MAX): 32470807\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 9422.836515565848\n", + ">> AVG(MAX): 32470807\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 2315.964770284498\n", + ">> MAX(MAX): 26240727\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 2315.964770284498\n", + ">> MIN(MAX): 26240727\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 2315.964770284498\n", + ">> AVG(MAX): 26240727\n", + "vis_col: INDISCARD\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 11.453699935354793\n", + ">> MAX(MAX): 8403755\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 11.453699935354793\n", + ">> MIN(MAX): 8403755\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 11.453699935354793\n", + ">> AVG(MAX): 8403755\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 102.17135060146234\n", + ">> MAX(MAX): 3169587\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 102.17135060146234\n", + ">> MIN(MAX): 3169587\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 102.17135060146234\n", + ">> AVG(MAX): 3169587\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 109.02586151696624\n", + ">> MAX(MAX): 3894820\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 109.02586151696624\n", + ">> MIN(MAX): 3894820\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 109.02586151696624\n", + ">> AVG(MAX): 3894820\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 124.03730567319344\n", + ">> MAX(MAX): 3365716\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 124.03730567319344\n", + ">> MIN(MAX): 3365716\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 124.03730567319344\n", + ">> AVG(MAX): 3365716\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 129.86653843994765\n", + ">> MAX(MAX): 9742979\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 129.86653843994765\n", + ">> MIN(MAX): 9742979\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 129.86653843994765\n", + ">> AVG(MAX): 9742979\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 101.42783862050769\n", + ">> MAX(MAX): 3252166\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 101.42783862050769\n", + ">> MIN(MAX): 3252166\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 101.42783862050769\n", + ">> AVG(MAX): 3252166\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 16.78371724870965\n", + ">> MAX(MAX): 877271\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 16.78371724870965\n", + ">> MIN(MAX): 877271\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 16.78371724870965\n", + ">> AVG(MAX): 877271\n", + "vis_col: INBCASTPPS\n", + "> plotting 20210620\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210621\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210622\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210623\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210624\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210625\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n", + "> plotting 20210626\n", + ">> MAX(MIN): 0\n", + ">> MAX(AVG): 0.0\n", + ">> MAX(MAX): 0\n", + ">> MIN(MIN): 0\n", + ">> MIN(AVG): 0.0\n", + ">> MIN(MAX): 0\n", + ">> AVG(MIN): 0\n", + ">> AVG(AVG): 0.0\n", + ">> AVG(MAX): 0\n" + ] + } + ], + "source": [ + "for vis_col in vis_cols:\n", + " print(f'vis_col: {vis_col}')\n", + " tmp_cols = []\n", + " \n", + " for col in cols:\n", + " #print(f'>>>>>col: {col}')\n", + " if vis_col in col:\n", + " tmp_cols.append(col)\n", + " \n", + " #print(tmp_cols)\n", + " #print('--------------------')\n", + " tmp_df = df[tmp_cols]\n", + " \n", + " # make tmp dataframe\n", + " tmp_df = pd.concat([dates_df, tmp_df], axis = 1)\n", + " \n", + " # for dates\n", + " for date in dates:\n", + " print(f'> plotting {date}')\n", + " \n", + " # use data at certain date\n", + " date_df = tmp_df[tmp_df['YYYYMMDD']==date].iloc[:,1:]\n", + " \n", + " criteria = ['MAX', 'MIN', 'AVG']\n", + " \n", + " for c in criteria:\n", + " \n", + " if c == 'AVG':\n", + " plot_df = date_df.iloc[:,0]\n", + " plot_avg = plot_df.mean()\n", + " plot_min = plot_df.min()\n", + " plot_max = plot_df.max()\n", + " print(f'>> AVG(MIN): {plot_min}')\n", + " print(f'>> AVG(AVG): {plot_avg}')\n", + " print(f'>> AVG(MAX): {plot_max}')\n", + "\n", + " elif c == 'MIN':\n", + " plot_df = date_df.iloc[:,1]\n", + " plot_avg = plot_df.mean()\n", + " plot_min = plot_df.min()\n", + " plot_max = plot_df.max()\n", + " print(f'>> MIN(MIN): {plot_min}')\n", + " print(f'>> MIN(AVG): {plot_avg}')\n", + " print(f'>> MIN(MAX): {plot_max}')\n", + " elif c == 'MAX':\n", + " plot_df = date_df.iloc[:,2]\n", + " plot_avg = plot_df.mean()\n", + " plot_min = plot_df.min()\n", + " plot_max = plot_df.max()\n", + " print(f'>> MAX(MIN): {plot_min}')\n", + " print(f'>> MAX(AVG): {plot_avg}')\n", + " print(f'>> MAX(MAX): {plot_max}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31923da3", + "metadata": { + "id": "31923da3" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "collapsed_sections": [], + "machine_shape": "hm", + "name": "Hamon_EDA.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/etc/test_info.csv b/etc/test_info.csv new file mode 100644 index 0000000..02e5c63 --- /dev/null +++ b/etc/test_info.csv @@ -0,0 +1,9 @@ +,C01,C02,C03,C04,C05,C06,C07,C08,C09,C10,C11,C12,C13,C14,C15,C16,C17,C18,C19,C20,C21,C22,C23,C24,C25,C26,C27,C28,C29,C30,C31,C32,C33,C34,C35,C36,C37,C38,C39,C40,C41,C42,C43,C44,C45,C46,C47,C48,C49,C50,C51,C52,C53,C54,C55,C56,C57,C58,C59,C60,C61,C62,C63,C64,C65,C66,C67,C68,C69,C70,C71,C72,C73,C74,C75,C76,C77,C78,C79,C80,C81,C82,C83,C84,C85,C86 +count,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0,274800.0 +mean,-2.690713361717612,0.00041848617176128096,12.083211255276565,-2.6023653566229986e-05,8.297552861062591,-0.3120051124454149,12.589179724890831,70.0,1.0,50.0,13251.349705240174,14.710806553457061,28.034372878165936,27050.774286754004,27.71467294581514,30.798442513791844,0.00011280931586608442,1.0,50.0,27.567075439701593,29.76383149796216,1.0,334.2999266182314,457.03519498948316,776.1617285298399,50.0,18271.534901746723,1.1185529979985442,1.0,54736.97572780204,993.203884737045,61.7955894588428,5.419255295123727,0.00011280931586608442,112.20986769701601,2880.0,25.56610018304222,0.0,0.0,78.25902647510917,7.729104944687045,0.00011838562590975255,14.874105055567691,11.953816232532748,84.94359995141922,25.0,80.62922604930856,0.9998871906841339,0.0,4929.470684133916,41.93711019734352,1.0,32.52107377085152,0.48547810986171774,0.0,334.0381702335882,456.23843434028373,17.816796929912666,49.330099638973806,720.0130115505823,0.9998871906841339,906.8498508005822,0.0,0.00011280931586608442,6987.690887918487,0.12581510385735079,9.279114564919938,9976.468133187773,0.999505094614265,321.3114397127729,20.876548724636102,8.760157998544397,244.31672755917032,296.4415334772561,31.294590227256183,48.790446494541484,1.1183014660844253,29.375247382569142,5.018883482423579,296.407937148035,366.6985281249271,1.0,993.2003626689228,12.003852831113539,50.0,1121.6063427947597 +std,0.5681280540025946,0.020452690857904385,0.2400350705119165,0.0016414225756156225,6.465559210823236,0.48106085818661865,0.057858468524922275,0.0,0.0,0.0,4153.1899031438315,3.409162383835392,0.0036753632482925476,71.70094250595464,0.772048310440249,3.719799654683417,0.010620593222309757,0.0,0.0,0.20362254904883526,0.7409660121868645,0.0,35.746581631979346,26.79836888880832,1314.8379458762295,0.0,1930.0727219859316,0.11229802459042486,0.0,89.5715663136732,31.413536307836782,11.085437424159368,0.6668449473052205,0.010620593222309757,7.9570470675043286,0.0,0.11157455286730868,0.0,0.0,148.23775618713944,0.5877156015581081,0.0020918972107001896,3.4370911168635327,0.2732193357622903,31.7853538898607,0.0,28.90658459963489,0.010620593222309757,0.0,5102.522608120266,4.793741692526357,0.0,31.20169737177613,0.3031595073388494,0.0,39.210911963147915,25.311289957876348,7.2184996284720375,1.5599016430941102,0.0730619310853684,0.010620593222309757,22.862428130689487,0.0,0.010620593222309757,6765.889692046581,0.038900994729483836,13.482452921384056,31.32189139646794,0.022241003899897034,47.55082342757309,15.211597309275012,6.271717235618787,15.525020693831664,415.22109941429875,3.772151468241192,1.4840426599620453,0.11136260954141612,0.36796069440622237,2.6904788145432303,415.2088832340863,59.69168937357197,0.0,31.06721269028631,0.15791451637071036,0.0,1700.3330700892282 +min,-4.38,0.0,11.781310000000001,-0.01128,0.27618000000000004,-1.0904,0.0,70.0,1.0,50.0,5728.0,0.26855,28.0195,26855.0,26.12927,0.0,0.0,1.0,50.0,27.33016,27.7771,1.0,232.69312000000002,226.45827999999997,-3.0,50.0,12758.0,0.77657,1.0,51648.0,913.32428,0.41963,0.0,0.0,0.0,2880.0,25.461389999999998,0.0,0.0,1.37329,0.0,-0.0319,0.0,2e-05,15.0,25.0,12.307739999999999,0.0,0.0,0.0,34.445190000000004,1.0,0.09042,0.30914,0.0,229.70923,410.71246,6.8288,43.35938,719.67841,0.0,0.0,0.0,0.0,-112.0,0.06324,0.0,9669.0,0.0,2.1849,0.0,0.0,208.03696000000002,7.15028,0.35248,42.6377,-0.012819999999999998,28.26935,2.40398,7.15028,230.52301,1.0,954.5495,12.0,50.0,1.0 +25%,-3.1289999999999996,0.0,11.90338,-0.00109,3.74756,-0.6093,12.5887,70.0,1.0,50.0,9518.0,12.84943,28.03166,26989.0,27.04294,28.447560000000003,0.0,1.0,50.0,27.33016,29.13513,1.0,313.784,433.22629000000006,3.0,50.0,17158.0,1.0484799999999999,1.0,54717.0,967.46063,56.49566,4.9334,0.0,108.24304,2880.0,25.461389999999998,0.0,0.0,4.99723,7.3751,-7e-05,12.958884999999999,11.907010000000001,100.0,25.0,60.599892499999996,1.0,0.0,120.0,37.619009999999996,1.0,0.2532,0.34424,0.0,308.4129,432.86947999999995,11.467260000000001,48.08197,719.96497,1.0,903.0,0.0,0.0,32.0,0.08793,0.0,9962.0,1.0,294.15405,0.0,3.90132,231.78097999999997,26.01891,28.87115,47.581759999999996,1.05377,29.148979999999998,2.85153,26.01891,319.73382999999995,1.0,966.99188,12.0,50.0,7.0 +50%,-2.7668,0.0,12.01782,0.0,6.28052,-0.4303,12.5887,70.0,1.0,50.0,13516.0,14.80255,28.034259999999996,27061.0,27.69424,30.406689999999998,0.0,1.0,50.0,27.554170000000003,29.86755,1.0,332.26636,460.47165,12.0,50.0,18171.0,1.11209,1.0,54738.0,983.11615,61.454730000000005,5.3311,0.0,112.25126999999999,2880.0,25.461389999999998,0.0,0.0,17.585729999999998,7.5982,7e-05,14.994025,11.953465,100.0,25.0,97.36022,1.0,0.0,3080.0,41.43371,1.0,23.20239,0.36713,0.0,333.0802,457.71722,20.44763,49.256890000000006,720.01581,1.0,907.0,0.0,0.0,4768.0,0.12549000000000002,2.240645,9973.0,1.0,319.97427000000005,26.66585,6.76975,238.64742999999999,91.56302,30.99213,48.542535,1.1186200000000002,29.35769,3.3442800000000004,91.56302,364.80035,1.0,980.1375099999999,12.0,50.0,61.0 +75%,-2.4478,0.0,12.36877,0.00101,13.833620000000002,-0.2435,12.58874,70.0,1.0,50.0,16990.0,16.54205,28.036859999999997,27103.0,28.402620000000002,32.5418,0.0,1.0,50.0,27.81151,30.310059999999996,1.0,351.59869,479.69162,970.0,50.0,19218.0,1.17945,1.0,54757.0,1023.1850599999999,66.22310999999999,5.6572,0.0,115.89333,2880.0,25.687170000000002,0.0,0.0,61.454730000000005,7.8422,0.00029,16.780907499999998,11.99618,100.0,25.0,97.37548000000001,1.0,0.0,9992.0,46.30127,1.0,66.18921,0.37933,0.0,355.68579,482.78879000000006,22.40454,50.56152,720.06061,1.0,911.0,0.0,0.0,14304.0,0.15045,13.9667375,9999.0,1.0,344.80163999999996,35.0,14.2204,258.48389,319.97427000000005,33.04443,49.917792500000004,1.18118,29.58042,8.81242,319.97427000000005,414.02631,1.0,1024.1756599999999,12.0,50.0,2355.0 +max,0.0,1.0,25.23956,0.01548,34.91364,1.4792,18.0,70.0,1.0,50.0,22711.0,92.37823,28.05423,27265.0,29.441470000000002,75.19748,1.0,1.0,50.0,27.81151,31.927490000000002,1.0,493.03747999999996,670.2044099999999,6080.0,50.0,26731.0,1.61973,1.0,55806.0,1063.68652,415.84015,7.5893,1.0,127.79274,2880.0,25.687170000000002,0.0,0.0,1221.50415,9.6698,0.033280000000000004,91.08211999999999,13.02161,100.0,25.0,97.68066,1.0,0.0,17768.0,49.93285,1.0,86.35339,1.53061,0.0,497.23309000000006,489.51122999999995,28.4608,57.786559999999994,720.26819,1.0,1106.0,0.0,1.0,20656.0,0.19749,67.14787,10248.0,1.0,1286.28479,40.0,35.038990000000005,282.70721000000003,2228.75806,76.51671999999999,57.88961,2.05933,31.02771,9.9604,2228.75806,499.78295999999995,1.0,1047.1856699999998,25.0,50.0,6927.0 diff --git a/etc/train_info.csv b/etc/train_info.csv new file mode 100644 index 0000000..f7d1cd8 --- /dev/null +++ b/etc/train_info.csv @@ -0,0 +1,9 @@ +,C01,C02,C03,C04,C05,C06,C07,C08,C09,C10,C11,C12,C13,C14,C15,C16,C17,C18,C19,C20,C21,C22,C23,C24,C25,C26,C27,C28,C29,C30,C31,C32,C33,C34,C35,C36,C37,C38,C39,C40,C41,C42,C43,C44,C45,C46,C47,C48,C49,C50,C51,C52,C53,C54,C55,C56,C57,C58,C59,C60,C61,C62,C63,C64,C65,C66,C67,C68,C69,C70,C71,C72,C73,C74,C75,C76,C77,C78,C79,C80,C81,C82,C83,C84,C85,C86 +count,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0,1004402.0 +mean,-2.068787571709336,0.0,12.244646957931186,-3.072509811808419e-05,65.07154146955104,0.44577336166196374,12.599763282639822,74.48028777322227,1.0,50.0,14693.801581438507,15.541538997264048,28.035262942327865,27210.896770416624,28.144403459122948,34.14727118754244,0.08009442434403755,1.0,50.0,27.417241166923173,31.427579729002932,1.0,331.1973085985991,449.4780387570912,781.2005571474369,50.0,18078.83650171943,1.105594034201445,1.0,54705.525781509794,1009.9753670177777,64.43072233442385,6.063227472864452,0.08009541996133022,113.52418833603467,2880.0,30.094778600420966,0.0,0.0,1633.1039159324844,8.464796172050635,0.00011299864994295116,15.682983392117888,11.993893181943086,36.34008943093502,22.759856113388864,32.70780895271017,0.9199045800386698,0.0,4821.710343069807,38.84628559887374,1.0,35.19280239248827,0.43801698743132744,0.0,330.92928451551285,448.66954795727196,14.309426565229863,50.663483122634155,720.0587924286391,0.9199055756559624,899.2094649353546,0.0,0.08009442434403755,7593.734795430515,0.12330798264041688,69.14063293854451,9972.942004297085,1.0,335.45187440361525,32.12630538990365,64.96661636830672,253.06461754758558,2202.2179012579027,34.721946107136375,50.07516692115308,1.1055778428059682,33.869057637360335,4.192900486169884,2202.20052452744,366.26226368724855,1.0,1009.9765101432093,12.000096351610212,50.0,1126.177493672852 +std,0.9973781779292777,0.0,0.13220908913816462,0.0016441980134274594,41.241220162838665,0.9490235841204151,0.23123955904435284,4.972919044472526,0.0,0.0,4239.378640242929,2.6242861412641942,0.004702159607627068,105.66174451344102,0.6865890759661545,4.697763331358924,0.2714394608186152,0.0,0.0,0.2435842597408327,1.0861409369376545,0.0,32.75944125354465,30.936915715712995,1312.3061733121647,0.0,1773.9917048343993,0.10444978700291914,0.0,140.0807066054632,39.98494551687945,8.033772199829684,1.1015370005999874,0.27144100099256646,8.377749784930145,0.0,2.8866167758266794,0.0,0.0,1130.3406615091844,0.9659159234903938,0.002097804379129603,2.609598865321592,0.10670483321058306,36.472913245517695,2.486459522236263,33.40571009462432,0.27144100099256646,0.0,5027.134653423027,3.6219558971385433,0.0,31.326284304003376,0.22844839384917232,0.0,36.29853863318136,30.388422949162763,13.198126162058122,3.0266593379149898,0.07449546482319407,0.2714394608186152,26.85508225932885,0.0,0.2714394608186152,6809.536105849556,0.04335728230399993,41.881694157686745,25.369391804062506,0.0,41.56541792025882,8.066558169633623,40.91532344854486,21.34890786115544,1329.7656914378495,4.7750404380439075,2.9476095714644055,0.08886520949378571,2.897106397948702,3.445795065515289,1329.7747584787655,60.61223958172202,0.0,39.815554778945646,0.017185548065648176,0.0,1693.60949796644 +min,-4.6271,0.0,11.9873,-0.04253,0.26855,-2.1467,12.03892,70.0,1.0,50.0,4705.0,0.26093,28.01602,26866.0,26.15353,12.07794,0.0,1.0,50.0,27.0,27.89917,1.0,233.09099999999998,373.26614,-38.0,50.0,12851.0,0.77193,1.0,54157.0,863.9603900000001,0.41963,3.4227,0.0,100.12769,2880.0,25.18253,0.0,0.0,2.13625,6.3222,-0.03986,0.0,11.70507,15.0,20.0,12.33826,0.0,0.0,-8.0,34.460440000000006,1.0,0.09042,0.30762,0.0,230.36029,392.17688,0.0,43.69507,719.51025,0.0,792.0,0.0,0.0,-128.0,0.054979999999999994,0.0,9826.0,1.0,2.1849,0.0,0.0,186.38612,11.12275,12.81891,43.30319,0.55328,28.158720000000002,0.0,11.12275,230.95702999999997,1.0,890.0452300000001,12.0,50.0,-112.0 +25%,-2.6891,0.0,12.10938,-0.00109,15.00092,-0.0902,12.53358,70.0,1.0,50.0,11417.0,13.9328,28.03172,27167.0,27.704159999999998,30.9869025,0.0,1.0,50.0,27.24697,30.96619,1.0,312.35535,422.79843,3.0,50.0,17053.0,1.0393,1.0,54710.0,978.3325199999999,59.35671,5.3848,0.0,106.89041,2880.0,26.92264,0.0,0.0,106.27747,7.6753,-7e-05,14.063802500000001,11.928230000000001,15.0,20.0,12.399289999999999,1.0,0.0,128.0,36.6272,1.0,0.63293,0.36255,0.0,306.80341,422.64315999999997,1.1065399999999999,48.91357,720.00726,1.0,898.0,0.0,0.0,112.0,0.09437999999999999,18.186609999999998,9960.0,1.0,309.0506,35.0,15.2188125,236.54935,553.35132,31.51093,48.3573,1.05301,30.833059999999996,0.0,553.35132,318.03387000000004,1.0,977.51953,12.0,50.0,7.0 +50%,-2.1586,0.0,12.26196,-7e-05,94.03381,0.4304,12.669310000000001,70.0,1.0,50.0,15124.0,15.59601,28.035140000000002,27230.0,28.04138,33.53791,0.0,1.0,50.0,27.33063,31.62231,1.0,330.6026,449.63482999999997,21.0,50.0,18051.0,1.10428,1.0,54722.0,1010.42865,63.934309999999996,5.9528,0.0,111.10626,2880.0,32.0,0.0,0.0,2479.9726600000004,8.4954,7e-05,15.708089999999999,11.98278,15.0,25.0,12.437439999999999,1.0,0.0,2984.0,37.16125,1.0,33.98077,0.36407,0.0,330.96429,448.11495999999994,13.623779999999998,49.98169,720.06299,1.0,903.0,0.0,0.0,7344.0,0.11492000000000001,100.0,9973.0,1.0,332.88461,35.0,93.76555,250.85446000000002,3176.86206,34.211729999999996,49.42992,1.11176,35.48735,5.32794,3176.86206,365.23438,1.0,1007.8375900000001,12.0,50.0,106.0 +75%,-1.5605,0.0,12.269589999999999,0.00101,100.51116,0.8929,12.75681,80.0,1.0,50.0,18276.0,17.26684,28.037840000000003,27268.0,28.60309,36.711200000000005,0.0,1.0,50.0,27.48978,32.019040000000004,1.0,349.82642000000004,476.47122,976.0,50.0,19096.0,1.1718674999999998,1.0,54774.0,1031.79565,68.51198000000001,6.5804,0.0,120.64178000000001,2880.0,32.188179999999996,0.0,0.0,2491.9890100000002,8.9554,0.00029,17.399607500000002,12.04491,62.7065875,25.0,44.5343,1.0,0.0,9592.0,39.6637,1.0,67.27435,0.36789,0.0,354.25708,476.10582999999997,21.25391,51.39312,720.11108,1.0,912.0,0.0,0.0,14560.0,0.16434,100.0,9999.0,1.0,356.71902,35.0,100.0,263.63372999999996,3184.74487,37.301629999999996,50.77159,1.16516,36.025240000000004,6.86263,3184.74487,414.69543,1.0,1030.6046099999999,12.0,50.0,2376.0 +max,0.8286,0.0,16.86249,0.040510000000000004,100.87737,3.1487,12.81139,80.0,1.0,50.0,22644.0,34.82971,28.05606,27543.0,30.46622,81.01099,1.0,1.0,50.0,27.943459999999998,34.8114,1.0,494.26721,535.8690799999999,6193.0,50.0,26826.0,1.62739,1.0,54832.0,1146.92163,222.81647999999998,9.1331,1.0,129.87657,2880.0,33.47964,0.0,0.0,2536.8115199999997,11.1379,0.03631,34.58655,12.28788,100.0,25.0,97.81036,1.0,0.0,13832.0,50.05493,1.0,94.34674,1.53671,0.0,496.85327,498.11957,50.0,66.71295,720.48914,1.0,936.0,0.0,1.0,19536.0,0.19972,100.0,10250.0,1.0,947.02161,35.0,100.0,332.48901,3190.0,82.4829,65.98333000000001,2.08832,38.054959999999994,10.0,3190.0,499.76489000000004,1.0,1121.85547,17.14934,50.0,12993.0 diff --git a/etc/val_info.csv b/etc/val_info.csv new file mode 100644 index 0000000..0d56abb --- /dev/null +++ b/etc/val_info.csv @@ -0,0 +1,9 @@ +,C01,C02,C03,C04,C05,C06,C07,C08,C09,C10,C11,C12,C13,C14,C15,C16,C17,C18,C19,C20,C21,C22,C23,C24,C25,C26,C27,C28,C29,C30,C31,C32,C33,C34,C35,C36,C37,C38,C39,C40,C41,C42,C43,C44,C45,C46,C47,C48,C49,C50,C51,C52,C53,C54,C55,C56,C57,C58,C59,C60,C61,C62,C63,C64,C65,C66,C67,C68,C69,C70,C71,C72,C73,C74,C75,C76,C77,C78,C79,C80,C81,C82,C83,C84,C85,C86 +count,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0,86400.0 +mean,-2.4594666620370367,0.0,11.935542401967592,-2.7098611111111107e-05,15.921492494907406,0.17047383333333332,12.743439570592129,70.0,1.0,50.0,13515.36855324074,15.071240775115744,28.034307578009265,27226.147638888888,28.135595587500003,30.357984739004632,0.08112268518518519,1.0,50.0,27.79620552,31.577997648379636,1.0,333.31510262800924,449.90493005300925,787.2582986111111,50.0,18186.160972222224,1.1148783346064814,1.0,54721.15542824074,1004.4912464424767,63.554135648958336,5.092231543981482,0.08112268518518519,116.31296652627316,2880.0,27.754849555562963,0.0,0.0,244.4950306193287,7.184605325231481,0.00011872546296296298,15.232709471180556,11.948349152893519,62.185901524537044,25.0,53.84042227233797,0.9188773148148148,0.0,4873.662592592593,42.72525996539351,1.0,32.67355743229167,0.5721718575231483,0.0,333.0438692743055,449.182239556117,20.989593509999995,49.95465788923612,719.9960670815972,0.9188773148148148,904.987337962963,0.0,0.08112268518518519,7048.826296296296,0.1267813355595833,21.455218706134257,9975.377488425926,1.0,330.7670292971065,30.26630022604167,16.171110291319444,249.5227628508102,684.2666456087962,30.848991297106473,49.40108099699074,1.114719238425926,31.54851779039352,0.716041982,684.2342972121528,365.849156715162,1.0,1004.4884641429628,12.001176364930556,50.0,1116.742673611111 +std,0.3484381851310685,0.0,0.22409287962325264,0.0016356237489022843,10.159001887790705,0.19563939071473177,0.1089069475918646,0.0,0.0,0.0,4019.8680651955415,2.8596862281705753,0.0033994924037676496,51.73052155844038,0.6125734158726767,3.3109409042541267,0.2730250133152174,0.0,0.0,0.0,0.5336158882978931,0.0,34.75362073885327,31.970357185144607,1324.7333685476513,0.0,1870.190511183838,0.11208207280905767,0.0,135.63765486819364,27.58101724844867,8.793604086361194,0.3837526229034144,0.2730250133152174,7.60802942999722,0.0,0.02979847117722374,0.0,0.0,493.33220886219846,0.27628479237301745,0.002022964623627249,2.8576262638098298,0.0445938488169702,40.772148640125664,0.0,28.03264136764282,0.2730250133152174,0.0,5104.584512387677,3.2402148348332633,0.0,31.344725601215686,0.2803459826107888,0.0,38.060102623143436,30.972669999548,3.5527342386646136e-15,1.5140082759702138,0.0696943795187874,0.2730250133152174,25.766570554632818,0.0,0.2730250133152174,6815.743654090211,0.04376930508883382,21.073703101866332,30.633440186657378,0.0,43.610062969993116,8.108487518719581,10.031640240294303,13.872905867558908,667.1978083164512,3.3611672180280143,1.427325460902682,0.10927432086600021,0.3399967804855059,0.0,667.0942712466791,59.099703930936855,0.0,27.234350782275367,0.05720268675172349,0.0,1695.1679011198223 +min,-3.2945,0.0,11.76605,-0.01251,0.3067,-0.5016,12.669310000000001,70.0,1.0,50.0,6038.0,0.28381,28.02125,27080.0,27.187559999999998,12.14206,0.0,1.0,50.0,27.79620552,30.157459999999997,1.0,238.82379,304.92278999999996,1.0,50.0,13065.0,0.7817,1.0,54285.0,859.9325,0.80104,4.184,0.0,100.30814000000001,2880.0,27.73684692,0.0,0.0,2.13625,6.5217,-0.02481,0.0,11.84436,15.0,25.0,12.39166,0.0,0.0,0.0,34.53674,1.0,0.09042,0.30990999999999996,0.0,235.42395,412.92023,20.98959351,44.89288,719.69604,0.0,815.0,0.0,0.0,-112.0,0.059444718,0.0,9752.0,1.0,4.17075,0.0,2.0647,184.61951000000002,11.12275,12.93335,43.64949,0.33432,30.602420000000002,0.716041982,11.12275,235.65900000000002,1.0,954.83789,12.0,50.0,5.0 +25%,-2.7718,0.0,11.78894,-0.00109,12.69684,0.0321,12.669310000000001,70.0,1.0,50.0,10060.0,13.337710000000001,28.03169,27200.0,27.75165,28.18937,0.0,1.0,50.0,27.79620552,31.31713,1.0,313.63934,422.33840999999995,3.0,50.0,17116.0,1.04253,1.0,54726.0,988.33459,58.78445,4.778575,0.0,110.19345,2880.0,27.73684692,0.0,0.0,53.062419999999996,7.0152,-7e-05,13.4501525,11.90833,15.0,25.0,36.93542,1.0,0.0,96.0,40.96069,1.0,0.18085,0.36255,0.0,308.75653,421.35715,20.98959351,48.79913,719.951155,1.0,906.0,0.0,0.0,32.0,0.10219,10.254865,9948.0,1.0,306.07104,26.579742500000002,13.047130000000001,240.93623,277.27127,28.63464,48.30546,1.04614,31.35277,0.716041982,277.27127,318.92004,1.0,985.22772,12.0,50.0,7.0 +50%,-2.4546,0.0,11.78894,-7e-05,14.5813,0.1776,12.669310000000001,70.0,1.0,50.0,14065.0,15.12299,28.034259999999996,27222.0,27.848209999999998,30.004830000000002,0.0,1.0,50.0,27.79620552,31.530759999999997,1.0,331.48871,436.70224,3.0,50.0,18094.0,1.11142,1.0,54757.0,1001.8158,63.36213000000001,5.0954,0.0,115.87123000000001,2880.0,27.73684692,0.0,0.0,97.12221,7.1770000000000005,7e-05,15.231355,11.947735,100.0,25.0,45.86181,1.0,0.0,2952.0,42.959590000000006,1.0,23.4375,0.47623000000000004,0.0,332.10364,433.32815999999997,20.98959351,49.974059999999994,719.9995700000001,1.0,912.0,0.0,0.0,5072.0,0.14577,16.535804999999996,9973.0,1.0,329.90546,35.0,14.97593,246.84904,505.68295,30.412290000000002,49.42156,1.11481,31.53244,0.716041982,505.68295,365.70459,1.0,995.8059099999999,12.0,50.0,85.0 +75%,-2.1376,0.0,12.26196,0.00101,16.22925,0.3348,12.90343761,70.0,1.0,50.0,17076.0,16.908260000000002,28.03683,27246.0,28.439759999999996,32.0202175,0.0,1.0,50.0,27.79620552,31.7749,1.0,351.58057,483.88320999999996,1004.0,50.0,19185.0,1.1795624999999998,1.0,54801.0,1021.59052,67.74902,5.4127,0.0,124.22188,2880.0,27.80418,0.0,0.0,165.97743,7.3947,0.00029,17.1111275,11.9886,100.0,25.0,86.2632725,1.0,0.0,9872.0,45.08056,1.0,66.31586,0.6845100000000001,0.0,355.16132000000005,483.27768,20.98959351,50.79803,720.04132,1.0,919.0,0.0,0.0,14336.0,0.15256,24.834087500000003,9999.0,1.0,352.74652000000003,35.0,16.36675,257.53021,817.42853,32.43408,50.323347500000004,1.18347,31.72928,0.716041982,817.42853,412.7785,1.0,1018.39404,12.0,50.0,2351.0 +max,-1.8027,0.0,16.389470000000003,0.00817,63.203430000000004,0.5817,12.90343761,70.0,1.0,50.0,19878.0,40.16265,28.04815,27410.0,29.80283,49.27771,1.0,1.0,50.0,27.79620552,33.42284,1.0,485.5686,535.40906,4169.0,50.0,26388.0,1.6022399999999999,1.0,54831.0,1068.93176,249.51932000000002,5.8265,1.0,129.60573,2880.0,27.80418,0.0,0.0,2424.65967,7.7867,0.026910000000000003,45.22703,12.02977,100.0,25.0,97.43652,1.0,0.0,13824.0,49.64294,1.0,84.00244,1.5267899999999999,0.0,495.51507999999995,494.23264000000006,20.98959351,55.40619,720.25458,1.0,930.0,0.0,1.0,17792.0,0.19333,100.0,10234.0,1.0,1007.90405,40.0,62.886309999999995,285.84432999999996,3140.57666,50.340270000000004,55.20247,2.05093,33.015209999999996,0.716041982,3140.57666,496.36499000000003,1.0,1046.19189,17.10766,50.0,5477.0 diff --git a/image/architecture.png b/image/architecture.png new file mode 100644 index 0000000..407324c Binary files /dev/null and b/image/architecture.png differ diff --git a/model/__init__.py b/model/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/model/org_vrae.py b/model/org_vrae.py new file mode 100644 index 0000000..a6bd2f6 --- /dev/null +++ b/model/org_vrae.py @@ -0,0 +1,502 @@ +import numpy as np +import torch +from torch import nn, optim +from torch import distributions +from sklearn.base import BaseEstimator +from torch.utils.data import DataLoader +from torch.autograd import Variable +import os + + + +class Encoder(nn.Module): + """ + Encoder network containing enrolled LSTM/GRU + + :param number_of_features: number of input features + :param hidden_size: hidden size of the RNN + :param hidden_layer_depth: number of layers in RNN + :param latent_length: latent vector length + :param dropout: percentage of nodes to dropout + :param block: LSTM/GRU block + """ + def __init__(self, number_of_features, hidden_size, hidden_layer_depth, latent_length, dropout, block = 'LSTM'): + + super(Encoder, self).__init__() + + self.number_of_features = number_of_features + self.hidden_size = hidden_size + self.hidden_layer_depth = hidden_layer_depth + self.latent_length = latent_length + + if block == 'LSTM': + self.model = nn.LSTM(self.number_of_features, self.hidden_size, self.hidden_layer_depth, dropout = dropout) + elif block == 'GRU': + self.model = nn.GRU(self.number_of_features, self.hidden_size, self.hidden_layer_depth, dropout = dropout) + else: + raise NotImplementedError + + def forward(self, x): + """Forward propagation of encoder. Given input, outputs the last hidden state of encoder + + :param x: input to the encoder, of shape (sequence_length, batch_size, number_of_features) + :return: last hidden state of encoder, of shape (batch_size, hidden_size) + """ + print('--------------------------') + print('DEBUGGING') + print(x.shape) + print('--------------------------') + + _, (h_end, c_end) = self.model(x) + + h_end = h_end[-1, :, :] + return h_end + + +class Lambda(nn.Module): + """Lambda module converts output of encoder to latent vector + + :param hidden_size: hidden size of the encoder + :param latent_length: latent vector length + """ + def __init__(self, hidden_size, latent_length): + super(Lambda, self).__init__() + + self.hidden_size = hidden_size + self.latent_length = latent_length + + self.hidden_to_mean = nn.Linear(self.hidden_size, self.latent_length) + self.hidden_to_logvar = nn.Linear(self.hidden_size, self.latent_length) + + nn.init.xavier_uniform_(self.hidden_to_mean.weight) + nn.init.xavier_uniform_(self.hidden_to_logvar.weight) + + def forward(self, cell_output): + """Given last hidden state of encoder, passes through a linear layer, and finds the mean and variance + + :param cell_output: last hidden state of encoder + :return: latent vector + """ + + self.latent_mean = self.hidden_to_mean(cell_output) + self.latent_logvar = self.hidden_to_logvar(cell_output) + + if self.training: + std = torch.exp(0.5 * self.latent_logvar) + eps = torch.randn_like(std) + return eps.mul(std).add_(self.latent_mean) + else: + return self.latent_mean + +class Decoder(nn.Module): + """Converts latent vector into output + + :param sequence_length: length of the input sequence + :param batch_size: batch size of the input sequence + :param hidden_size: hidden size of the RNN + :param hidden_layer_depth: number of layers in RNN + :param latent_length: latent vector length + :param output_size: 2, one representing the mean, other log std dev of the output + :param block: GRU/LSTM - use the same which you've used in the encoder + :param dtype: Depending on cuda enabled/disabled, create the tensor + """ + def __init__(self, sequence_length, batch_size, hidden_size, hidden_layer_depth, latent_length, output_size, dtype, block='LSTM'): + + super(Decoder, self).__init__() + + self.hidden_size = hidden_size + self.batch_size = batch_size + self.sequence_length = sequence_length + self.hidden_layer_depth = hidden_layer_depth + self.latent_length = latent_length + self.output_size = output_size + self.dtype = dtype + + if block == 'LSTM': + self.model = nn.LSTM(1, self.hidden_size, self.hidden_layer_depth) + elif block == 'GRU': + self.model = nn.GRU(1, self.hidden_size, self.hidden_layer_depth) + else: + raise NotImplementedError + + self.latent_to_hidden = nn.Linear(self.latent_length, self.hidden_size) + self.hidden_to_output = nn.Linear(self.hidden_size, self.output_size) + + self.decoder_inputs = torch.zeros(self.sequence_length, self.batch_size, 1, requires_grad=True).type(self.dtype) + self.c_0 = torch.zeros(self.hidden_layer_depth, self.batch_size, self.hidden_size, requires_grad=True).type(self.dtype) + + nn.init.xavier_uniform_(self.latent_to_hidden.weight) + nn.init.xavier_uniform_(self.hidden_to_output.weight) + + def forward(self, latent): + """Converts latent to hidden to output + + :param latent: latent vector + :return: outputs consisting of mean and std dev of vector + """ + h_state = self.latent_to_hidden(latent) + + if isinstance(self.model, nn.LSTM): + h_0 = torch.stack([h_state for _ in range(self.hidden_layer_depth)]) + decoder_output, _ = self.model(self.decoder_inputs, (h_0, self.c_0)) + elif isinstance(self.model, nn.GRU): + h_0 = torch.stack([h_state for _ in range(self.hidden_layer_depth)]) + decoder_output, _ = self.model(self.decoder_inputs, h_0) + else: + raise NotImplementedError + + out = self.hidden_to_output(decoder_output) + return out + +def _assert_no_grad(tensor): + assert not tensor.requires_grad, \ + "nn criterions don't compute the gradient w.r.t. targets - please " \ + "mark these tensors as not requiring gradients" + +class VRAE(BaseEstimator, nn.Module): + """Variational recurrent auto-encoder. This module is used for dimensionality reduction of timeseries + + :param sequence_length: length of the input sequence + :param number_of_features: number of input features + :param hidden_size: hidden size of the RNN + :param hidden_layer_depth: number of layers in RNN + :param latent_length: latent vector length + :param batch_size: number of timeseries in a single batch + :param learning_rate: the learning rate of the module + :param block: GRU/LSTM to be used as a basic building block + :param n_epochs: Number of iterations/epochs + :param dropout_rate: The probability of a node being dropped-out + :param optimizer: ADAM/ SGD optimizer to reduce the loss function + :param loss: SmoothL1Loss / MSELoss / ReconLoss / any custom loss which inherits from `_Loss` class + :param boolean cuda: to be run on GPU or not + :param print_every: The number of iterations after which loss should be printed + :param boolean clip: Gradient clipping to overcome explosion + :param max_grad_norm: The grad-norm to be clipped + :param dload: Download directory where models are to be dumped + """ + def __init__(self, sequence_length, number_of_features, hidden_size=90, hidden_layer_depth=2, latent_length=20, + batch_size=32, learning_rate=0.005, block='LSTM', + n_epochs=5, dropout_rate=0., optimizer='Adam', loss='MSELoss', + cuda=False, print_every=100, clip=True, max_grad_norm=5, dload='.'): + + super(VRAE, self).__init__() + + + self.dtype = torch.FloatTensor + self.use_cuda = cuda + + if not torch.cuda.is_available() and self.use_cuda: + self.use_cuda = False + + + if self.use_cuda: + self.dtype = torch.cuda.FloatTensor + + + self.encoder = Encoder(number_of_features = number_of_features, + hidden_size=hidden_size, + hidden_layer_depth=hidden_layer_depth, + latent_length=latent_length, + dropout=dropout_rate, + block=block) + + self.lmbd = Lambda(hidden_size=hidden_size, + latent_length=latent_length) + + self.decoder = Decoder(sequence_length=sequence_length, + batch_size = batch_size, + hidden_size=hidden_size, + hidden_layer_depth=hidden_layer_depth, + latent_length=latent_length, + output_size=number_of_features, + block=block, + dtype=self.dtype) + + self.sequence_length = sequence_length + self.hidden_size = hidden_size + self.hidden_layer_depth = hidden_layer_depth + self.latent_length = latent_length + self.batch_size = batch_size + self.learning_rate = learning_rate + self.n_epochs = n_epochs + + self.print_every = print_every + self.clip = clip + self.max_grad_norm = max_grad_norm + self.is_fitted = False + self.dload = dload + + if self.use_cuda: + self.cuda() + + if optimizer == 'Adam': + self.optimizer = optim.Adam(self.parameters(), lr=learning_rate) + elif optimizer == 'SGD': + self.optimizer = optim.SGD(self.parameters(), lr=learning_rate) + else: + raise ValueError('Not a recognized optimizer') + + if loss == 'SmoothL1Loss': + self.loss_fn = nn.SmoothL1Loss(size_average=False) + elif loss == 'MSELoss': + self.loss_fn = nn.MSELoss(size_average=False) + + def __repr__(self): + return """VRAE(n_epochs={n_epochs},batch_size={batch_size},cuda={cuda})""".format( + n_epochs=self.n_epochs, + batch_size=self.batch_size, + cuda=self.use_cuda) + + def forward(self, x): + """ + Forward propagation which involves one pass from inputs to encoder to lambda to decoder + + :param x:input tensor + :return: the decoded output, latent vector + """ + cell_output = self.encoder(x) + latent = self.lmbd(cell_output) + x_decoded = self.decoder(latent) + + return x_decoded, latent + + def _rec(self, x_decoded, x, loss_fn): + """ + Compute the loss given output x decoded, input x and the specified loss function + + :param x_decoded: output of the decoder + :param x: input to the encoder + :param loss_fn: loss function specified + :return: joint loss, reconstruction loss and kl-divergence loss + """ + latent_mean, latent_logvar = self.lmbd.latent_mean, self.lmbd.latent_logvar + + kl_loss = -0.5 * torch.mean(1 + latent_logvar - latent_mean.pow(2) - latent_logvar.exp()) + recon_loss = loss_fn(x_decoded, x) + + return kl_loss + recon_loss, recon_loss, kl_loss + + def compute_loss(self, X): + """ + Given input tensor, forward propagate, compute the loss, and backward propagate. + Represents the lifecycle of a single iteration + + :param X: Input tensor + :return: total loss, reconstruction loss, kl-divergence loss and original input + """ + x = Variable(X[:,:,:].type(self.dtype), requires_grad = True) + + x_decoded, _ = self(x) + loss, recon_loss, kl_loss = self._rec(x_decoded, x.detach(), self.loss_fn) + + return loss, recon_loss, kl_loss, x + + + def _train(self, train_loader): + """ + For each epoch, given the batch_size, run this function batch_size * num_of_batches number of times + + :param train_loader:input train loader with shuffle + :return: + """ + self.train() + + epoch_loss = 0 + t = 0 + + for t, X in enumerate(train_loader): + + # Index first element of array to return tensor + X = X[0] + + # required to swap axes, since dataloader gives output in (batch_size x seq_len x num_of_features) + X = X.permute(1,0,2) + + self.optimizer.zero_grad() + loss, recon_loss, kl_loss, _ = self.compute_loss(X) + loss.backward() + + if self.clip: + torch.nn.utils.clip_grad_norm_(self.parameters(), max_norm = self.max_grad_norm) + + # accumulator + epoch_loss += loss.item() + + self.optimizer.step() + + if (t + 1) % self.print_every == 0: + print('Batch %d, loss = %.4f, recon_loss = %.4f, kl_loss = %.4f' % (t + 1, loss.item(), + recon_loss.item(), kl_loss.item())) + + print('Average loss: {:.4f}'.format(epoch_loss / t)) + + + def fit(self, dataset, save = False): + """ + Calls `_train` function over a fixed number of epochs, specified by `n_epochs` + + :param dataset: `Dataset` object + :param bool save: If true, dumps the trained model parameters as pickle file at `dload` directory + :return: + """ + + train_loader = DataLoader(dataset = dataset, + batch_size = self.batch_size, + shuffle = True, + drop_last=True) + + ######################### + # debugging + print('fit result') + tmp = iter(train_loader).next()[0] + print(tmp.shape) + ########################### + + for i in range(self.n_epochs): + print('Epoch: %s' % i) + + self._train(train_loader) + + self.is_fitted = True + if save: + self.save('model.pth') + + + def _batch_transform(self, x): + """ + Passes the given input tensor into encoder and lambda function + + :param x: input batch tensor + :return: intermediate latent vector + """ + return self.lmbd( + self.encoder( + Variable(x.type(self.dtype), requires_grad = False) + ) + ).cpu().data.numpy() + + def _batch_reconstruct(self, x): + """ + Passes the given input tensor into encoder, lambda and decoder function + + :param x: input batch tensor + :return: reconstructed output tensor + """ + + x = Variable(x.type(self.dtype), requires_grad = False) + x_decoded, _ = self(x) + + return x_decoded.cpu().data.numpy() + + def reconstruct(self, dataset, save = False): + """ + Given input dataset, creates dataloader, runs dataloader on `_batch_reconstruct` + Prerequisite is that model has to be fit + + :param dataset: input dataset who's output vectors are to be obtained + :param bool save: If true, dumps the output vector dataframe as a pickle file + :return: + """ + + self.eval() + + test_loader = DataLoader(dataset = dataset, + batch_size = self.batch_size, + shuffle = False, + drop_last=True) # Don't shuffle for test_loader + + if self.is_fitted: + with torch.no_grad(): + x_decoded = [] + + for t, x in enumerate(test_loader): + x = x[0] + x = x.permute(1, 0, 2) + + x_decoded_each = self._batch_reconstruct(x) + x_decoded.append(x_decoded_each) + + x_decoded = np.concatenate(x_decoded, axis=1) + + if save: + if os.path.exists(self.dload): + pass + else: + os.mkdir(self.dload) + x_decoded.dump(self.dload + '/z_run.pkl') + return x_decoded + + raise RuntimeError('Model needs to be fit') + + + def transform(self, dataset, save = False): + """ + Given input dataset, creates dataloader, runs dataloader on `_batch_transform` + Prerequisite is that model has to be fit + + :param dataset: input dataset who's latent vectors are to be obtained + :param bool save: If true, dumps the latent vector dataframe as a pickle file + :return: + """ + self.eval() + + test_loader = DataLoader(dataset = dataset, + batch_size = self.batch_size, + shuffle = False, + drop_last=True) # Don't shuffle for test_loader + if self.is_fitted: + with torch.no_grad(): + z_run = [] + + for t, x in enumerate(test_loader): + x = x[0] + x = x.permute(1, 0, 2) + + z_run_each = self._batch_transform(x) + z_run.append(z_run_each) + + z_run = np.concatenate(z_run, axis=0) + if save: + if os.path.exists(self.dload): + pass + else: + os.mkdir(self.dload) + z_run.dump(self.dload + '/z_run.pkl') + return z_run + + raise RuntimeError('Model needs to be fit') + + def fit_transform(self, dataset, save = False): + """ + Combines the `fit` and `transform` functions above + + :param dataset: Dataset on which fit and transform have to be performed + :param bool save: If true, dumps the model and latent vectors as pickle file + :return: latent vectors for input dataset + """ + self.fit(dataset, save = save) + return self.transform(dataset, save = save) + + def save(self, file_name): + """ + Pickles the model parameters to be retrieved later + + :param file_name: the filename to be saved as,`dload` serves as the download directory + :return: None + """ + PATH = self.dload + '/' + file_name + if os.path.exists(self.dload): + pass + else: + os.mkdir(self.dload) + torch.save(self.state_dict(), PATH) + + def load(self, PATH): + """ + Loads the model's parameters from the path mentioned + + :param PATH: Should contain pickle file + :return: None + """ + self.is_fitted = True + self.load_state_dict(torch.load(PATH)) \ No newline at end of file diff --git a/model/utils.py b/model/utils.py new file mode 100644 index 0000000..3ec8ba4 --- /dev/null +++ b/model/utils.py @@ -0,0 +1,49 @@ +import os +import numpy as np +import glob +import pandas as pd + + +def load_data(folder, cols_to_remove = None): + """ + folder: folder where data is located + """ + # define path + data_path = f'./{folder}/*.csv' + + # get data + file_list = glob.glob(data_path) + file_list.sort() + + # load dataset + df_total = pd.DataFrame() + + for i in file_list: + data = pd.read_csv(i) + df_total = pd.concat([df_total, data]) + + # Sort by date + df_total = df_total.reset_index(drop = True) + df_total = df_total.drop(cols_to_remove, axis=1) + df_total = df_total.to_numpy() + + return df_total + +# TODO : Delete function +def open_data(direc, ratio_train=0.8, dataset="ECG5000"): + """Input: + direc: location of the UCR archive + ratio_train: ratio to split training and testset + dataset: name of the dataset in the UCR archive""" + datadir = direc + '/' + dataset + '/' + dataset + data_train = np.loadtxt(datadir + '_TRAIN', delimiter=',') + data_test_val = np.loadtxt(datadir + '_TEST', delimiter=',')[:-1] + data = np.concatenate((data_train, data_test_val), axis=0) + data = np.expand_dims(data, -1) + + N, D, _ = data.shape + + ind_cut = int(ratio_train * N) + ind = np.random.permutation(N) + return data[ind[:ind_cut], 1:, :], data[ind[ind_cut:], 1:, :], data[ind[:ind_cut], 0, :], data[ind[ind_cut:], 0, :] + diff --git a/model/vrae.py b/model/vrae.py new file mode 100644 index 0000000..66fa9e0 --- /dev/null +++ b/model/vrae.py @@ -0,0 +1,492 @@ +import numpy as np +import torch +from torch import nn, optim +from torch import distributions +from sklearn.base import BaseEstimator +from torch.utils.data import DataLoader +from torch.autograd import Variable +import os + + +class Encoder(nn.Module): + """ + Encoder network containing enrolled LSTM/GRU + + :param number_of_features: number of input features + :param hidden_size: hidden size of the RNN + :param hidden_layer_depth: number of layers in RNN + :param latent_length: latent vector length + :param dropout: percentage of nodes to dropout + :param block: LSTM/GRU block + """ + def __init__(self, number_of_features, hidden_size, hidden_layer_depth, latent_length, dropout, block = 'LSTM'): + + super(Encoder, self).__init__() + + self.number_of_features = number_of_features + self.hidden_size = hidden_size + self.hidden_layer_depth = hidden_layer_depth + self.latent_length = latent_length + + if block == 'LSTM': + self.model = nn.LSTM(self.number_of_features, self.hidden_size, self.hidden_layer_depth, dropout = dropout) + elif block == 'GRU': + self.model = nn.GRU(self.number_of_features, self.hidden_size, self.hidden_layer_depth, dropout = dropout) + else: + raise NotImplementedError + + def forward(self, x): + """Forward propagation of encoder. Given input, outputs the last hidden state of encoder + + :param x: input to the encoder, of shape (sequence_length, batch_size, number_of_features) + :return: last hidden state of encoder, of shape (batch_size, hidden_size) + """ + + print('--------------------------') + print('DEBUGGING') + print(x.shape) + print('--------------------------') + + _, (h_end, c_end) = self.model(x) + + h_end = h_end[-1, :, :] + return h_end + + +class Lambda(nn.Module): + """Lambda module converts output of encoder to latent vector + + :param hidden_size: hidden size of the encoder + :param latent_length: latent vector length + """ + def __init__(self, hidden_size, latent_length): + super(Lambda, self).__init__() + + self.hidden_size = hidden_size + self.latent_length = latent_length + + self.hidden_to_mean = nn.Linear(self.hidden_size, self.latent_length) + self.hidden_to_logvar = nn.Linear(self.hidden_size, self.latent_length) + + nn.init.xavier_uniform_(self.hidden_to_mean.weight) + nn.init.xavier_uniform_(self.hidden_to_logvar.weight) + + def forward(self, cell_output): + """Given last hidden state of encoder, passes through a linear layer, and finds the mean and variance + + :param cell_output: last hidden state of encoder + :return: latent vector + """ + + self.latent_mean = self.hidden_to_mean(cell_output) + self.latent_logvar = self.hidden_to_logvar(cell_output) + + if self.training: + std = torch.exp(0.5 * self.latent_logvar) + eps = torch.randn_like(std) + return eps.mul(std).add_(self.latent_mean) + else: + return self.latent_mean + +class Decoder(nn.Module): + """Converts latent vector into output + + :param sequence_length: length of the input sequence + :param batch_size: batch size of the input sequence + :param hidden_size: hidden size of the RNN + :param hidden_layer_depth: number of layers in RNN + :param latent_length: latent vector length + :param output_size: 2, one representing the mean, other log std dev of the output + :param block: GRU/LSTM - use the same which you've used in the encoder + :param dtype: Depending on cuda enabled/disabled, create the tensor + """ + def __init__(self, sequence_length, batch_size, hidden_size, hidden_layer_depth, latent_length, output_size, dtype, block='LSTM'): + + super(Decoder, self).__init__() + + self.hidden_size = hidden_size + self.batch_size = batch_size + self.sequence_length = sequence_length + self.hidden_layer_depth = hidden_layer_depth + self.latent_length = latent_length + self.output_size = output_size + self.dtype = dtype + + if block == 'LSTM': + self.model = nn.LSTM(1, self.hidden_size, self.hidden_layer_depth) + elif block == 'GRU': + self.model = nn.GRU(1, self.hidden_size, self.hidden_layer_depth) + else: + raise NotImplementedError + + self.latent_to_hidden = nn.Linear(self.latent_length, self.hidden_size) + self.hidden_to_output = nn.Linear(self.hidden_size, self.output_size) + + self.decoder_inputs = torch.zeros(self.sequence_length, self.batch_size, 1, requires_grad=True).type(self.dtype) + self.c_0 = torch.zeros(self.hidden_layer_depth, self.batch_size, self.hidden_size, requires_grad=True).type(self.dtype) + + nn.init.xavier_uniform_(self.latent_to_hidden.weight) + nn.init.xavier_uniform_(self.hidden_to_output.weight) + + def forward(self, latent): + """Converts latent to hidden to output + + :param latent: latent vector + :return: outputs consisting of mean and std dev of vector + """ + h_state = self.latent_to_hidden(latent) + + if isinstance(self.model, nn.LSTM): + h_0 = torch.stack([h_state for _ in range(self.hidden_layer_depth)]) + decoder_output, _ = self.model(self.decoder_inputs, (h_0, self.c_0)) + elif isinstance(self.model, nn.GRU): + h_0 = torch.stack([h_state for _ in range(self.hidden_layer_depth)]) + decoder_output, _ = self.model(self.decoder_inputs, h_0) + else: + raise NotImplementedError + + out = self.hidden_to_output(decoder_output) + return out + +def _assert_no_grad(tensor): + assert not tensor.requires_grad, \ + "nn criterions don't compute the gradient w.r.t. targets - please " \ + "mark these tensors as not requiring gradients" + +class VRAE(BaseEstimator, nn.Module): + """Variational recurrent auto-encoder. This module is used for dimensionality reduction of timeseries + + :param sequence_length: length of the input sequence + :param number_of_features: number of input features + :param hidden_size: hidden size of the RNN + :param hidden_layer_depth: number of layers in RNN + :param latent_length: latent vector length + :param batch_size: number of timeseries in a single batch + :param learning_rate: the learning rate of the module + :param block: GRU/LSTM to be used as a basic building block + :param n_epochs: Number of iterations/epochs + :param dropout_rate: The probability of a node being dropped-out + :param optimizer: ADAM/ SGD optimizer to reduce the loss function + :param loss: SmoothL1Loss / MSELoss / ReconLoss / any custom loss which inherits from `_Loss` class + :param boolean cuda: to be run on GPU or not + :param print_every: The number of iterations after which loss should be printed + :param boolean clip: Gradient clipping to overcome explosion + :param max_grad_norm: The grad-norm to be clipped + :param dload: Download directory where models are to be dumped + """ + def __init__(self, sequence_length, number_of_features, hidden_size=90, hidden_layer_depth=2, latent_length=20, + batch_size=32, learning_rate=0.005, block='LSTM', + n_epochs=5, dropout_rate=0., optimizer='Adam', loss='MSELoss', + cuda=False, print_every=100, clip=True, max_grad_norm=5, dload='.'): + + super(VRAE, self).__init__() + + + self.dtype = torch.FloatTensor + self.use_cuda = cuda + + if not torch.cuda.is_available() and self.use_cuda: + self.use_cuda = False + + + if self.use_cuda: + self.dtype = torch.cuda.FloatTensor + + + self.encoder = Encoder(number_of_features = number_of_features, + hidden_size=hidden_size, + hidden_layer_depth=hidden_layer_depth, + latent_length=latent_length, + dropout=dropout_rate, + block=block) + + self.lmbd = Lambda(hidden_size=hidden_size, + latent_length=latent_length) + + self.decoder = Decoder(sequence_length=sequence_length, + batch_size = batch_size, + hidden_size=hidden_size, + hidden_layer_depth=hidden_layer_depth, + latent_length=latent_length, + output_size=number_of_features, + block=block, + dtype=self.dtype) + + self.sequence_length = sequence_length + self.hidden_size = hidden_size + self.hidden_layer_depth = hidden_layer_depth + self.latent_length = latent_length + self.batch_size = batch_size + self.learning_rate = learning_rate + self.n_epochs = n_epochs + + self.print_every = print_every + self.clip = clip + self.max_grad_norm = max_grad_norm + self.is_fitted = False + self.dload = dload + + if self.use_cuda: + self.cuda() + + if optimizer == 'Adam': + self.optimizer = optim.Adam(self.parameters(), lr=learning_rate) + elif optimizer == 'SGD': + self.optimizer = optim.SGD(self.parameters(), lr=learning_rate) + else: + raise ValueError('Not a recognized optimizer') + + if loss == 'SmoothL1Loss': + self.loss_fn = nn.SmoothL1Loss(size_average=False) + elif loss == 'MSELoss': + self.loss_fn = nn.MSELoss(size_average=False) + + def __repr__(self): + return """VRAE(n_epochs={n_epochs},batch_size={batch_size},cuda={cuda})""".format( + n_epochs=self.n_epochs, + batch_size=self.batch_size, + cuda=self.use_cuda) + + def forward(self, x): + """ + Forward propagation which involves one pass from inputs to encoder to lambda to decoder + + :param x:input tensor + :return: the decoded output, latent vector + """ + cell_output = self.encoder(x) + latent = self.lmbd(cell_output) + x_decoded = self.decoder(latent) + + return x_decoded, latent + + def _rec(self, x_decoded, x, loss_fn): + """ + Compute the loss given output x decoded, input x and the specified loss function + + :param x_decoded: output of the decoder + :param x: input to the encoder + :param loss_fn: loss function specified + :return: joint loss, reconstruction loss and kl-divergence loss + """ + latent_mean, latent_logvar = self.lmbd.latent_mean, self.lmbd.latent_logvar + + kl_loss = -0.5 * torch.mean(1 + latent_logvar - latent_mean.pow(2) - latent_logvar.exp()) + recon_loss = loss_fn(x_decoded, x) + + return kl_loss + recon_loss, recon_loss, kl_loss + + def compute_loss(self, X): + """ + Given input tensor, forward propagate, compute the loss, and backward propagate. + Represents the lifecycle of a single iteration + + :param X: Input tensor + :return: total loss, reconstruction loss, kl-divergence loss and original input + """ + x = Variable(X[:,:,:].type(self.dtype), requires_grad = True) + + x_decoded, _ = self(x) + loss, recon_loss, kl_loss = self._rec(x_decoded, x.detach(), self.loss_fn) + + return loss, recon_loss, kl_loss, x + + + def _train(self, train_loader): + """ + For each epoch, given the batch_size, run this function batch_size * num_of_batches number of times + + :param train_loader:input train loader with shuffle + :return: + """ + self.train() + + epoch_loss = 0 + t = 0 + + for t, X in enumerate(train_loader): + + self.optimizer.zero_grad() + loss, recon_loss, kl_loss, _ = self.compute_loss(X) + loss.backward() + + if self.clip: + torch.nn.utils.clip_grad_norm_(self.parameters(), max_norm = self.max_grad_norm) + + # accumulator + epoch_loss += loss.item() + + self.optimizer.step() + + if (t + 1) % self.print_every == 0: + print('Batch %d, loss = %.4f, recon_loss = %.4f, kl_loss = %.4f' % (t + 1, loss.item(), + recon_loss.item(), kl_loss.item())) + + print('Average loss: {:.4f}'.format(epoch_loss / t)) + + + def fit(self, dataset, save = False): + """ + Calls `_train` function over a fixed number of epochs, specified by `n_epochs` + + :param dataset: `Dataset` object + :param bool save: If true, dumps the trained model parameters as pickle file at `dload` directory + :return: + """ + + train_loader = DataLoader(dataset = dataset, + batch_size = self.batch_size, + shuffle = False, + drop_last=True) + + #################### + print('debugging') + print('fit result') + print(dataset) + print(dataset[0]) + tmp = iter(train_loader).next() + print(tmp.shape) + #################### + + for i in range(self.n_epochs): + print('Epoch: %s' % i) + + self._train(train_loader) + + self.is_fitted = True + if save: + self.save('model.pth') + + + def _batch_transform(self, x): + """ + Passes the given input tensor into encoder and lambda function + + :param x: input batch tensor + :return: intermediate latent vector + """ + return self.lmbd( + self.encoder( + Variable(x.type(self.dtype), requires_grad = False) + ) + ).cpu().data.numpy() + + def _batch_reconstruct(self, x): + """ + Passes the given input tensor into encoder, lambda and decoder function + + :param x: input batch tensor + :return: reconstructed output tensor + """ + + x = Variable(x.type(self.dtype), requires_grad = False) + x_decoded, _ = self(x) + + return x_decoded.cpu().data.numpy() + + def reconstruct(self, dataset, save = False): + """ + Given input dataset, creates dataloader, runs dataloader on `_batch_reconstruct` + Prerequisite is that model has to be fit + + :param dataset: input dataset who's output vectors are to be obtained + :param bool save: If true, dumps the output vector dataframe as a pickle file + :return: + """ + + self.eval() + + test_loader = DataLoader(dataset = dataset, + batch_size = self.batch_size, + shuffle = False, + drop_last=True) # Don't shuffle for test_loader + + if self.is_fitted: + with torch.no_grad(): + x_decoded = [] + + for t, x in enumerate(test_loader): + x_decoded_each = self._batch_reconstruct(x) + x_decoded.append(x_decoded_each) + + x_decoded = np.concatenate(x_decoded, axis=1) + + if save: + if os.path.exists(self.dload): + pass + else: + os.mkdir(self.dload) + x_decoded.dump(self.dload + '/z_run.pkl') + return x_decoded + + raise RuntimeError('Model needs to be fit') + + + def transform(self, dataset, save = False): + """ + Given input dataset, creates dataloader, runs dataloader on `_batch_transform` + Prerequisite is that model has to be fit + + :param dataset: input dataset who's latent vectors are to be obtained + :param bool save: If true, dumps the latent vector dataframe as a pickle file + :return: + """ + self.eval() + + test_loader = DataLoader(dataset = dataset, + batch_size = self.batch_size, + shuffle = False, + drop_last=True) # Don't shuffle for test_loader + if self.is_fitted: + with torch.no_grad(): + z_run = [] + + for t, x in enumerate(test_loader): + z_run_each = self._batch_transform(x) + z_run.append(z_run_each) + + z_run = np.concatenate(z_run, axis=0) + if save: + if os.path.exists(self.dload): + pass + else: + os.mkdir(self.dload) + z_run.dump(self.dload + '/z_run.pkl') + return z_run + + raise RuntimeError('Model needs to be fit') + + def fit_transform(self, dataset, save = False): + """ + Combines the `fit` and `transform` functions above + + :param dataset: Dataset on which fit and transform have to be performed + :param bool save: If true, dumps the model and latent vectors as pickle file + :return: latent vectors for input dataset + """ + self.fit(dataset, save = save) + return self.transform(dataset, save = save) + + def save(self, file_name): + """ + Pickles the model parameters to be retrieved later + + :param file_name: the filename to be saved as,`dload` serves as the download directory + :return: None + """ + PATH = self.dload + '/' + file_name + if os.path.exists(self.dload): + pass + else: + os.mkdir(self.dload) + torch.save(self.state_dict(), PATH) + + def load(self, PATH): + """ + Loads the model's parameters from the path mentioned + + :param PATH: Should contain pickle file + :return: None + """ + self.is_fitted = True + self.load_state_dict(torch.load(PATH)) \ No newline at end of file diff --git a/model_dir/vrae.pth b/model_dir/vrae.pth new file mode 100644 index 0000000..c3eb206 Binary files /dev/null and b/model_dir/vrae.pth differ diff --git a/params.txt b/params.txt new file mode 100644 index 0000000..6272edd --- /dev/null +++ b/params.txt @@ -0,0 +1,14 @@ +hidden_size = 90 +hidden_layer_depth = 1 +latent_length = 20 +batch_size = 100 +learning_rate = 0.0005 +n_epochs = 50 +dropout_rate = 0.2 +optimizer = 'Adam' +cuda = True +print_every=30 +clip = True +max_grad_norm=5 +loss = 'MSELoss' +block = 'LSTM' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..fe1979c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +matplotlib==3.3.4 +numpy==1.19.5 +plotly==5.4.0 +scikit-learn==0.24.2 +scipy==1.5.4 +torch==1.10.0 +torchvision==0.11.1 \ No newline at end of file