<jupyter_start><jupyter_text>Analysis Classes - a Unified Interface to Analysis ResultsMVG comes with a set of analysis classes which provide a unified interface to analysis results *irrespective of the specific feature*. Note that the analysis classes are helper classes, as such the mvg class does *not* depend on them.Except for step (1) requesting the specific feature analysis, the following generic workflow holds:1. Request a specific analysis2. Retrieve results and parse them into an analysis_class object3. Use generic methods like plot(), summary() or to_df()One application is to use the analysis classes interactively from a Python REPL session. Or in (pseudo) code```pythonresult = parse_results(session.get_analysis_results(request_id))   call API to get resultsresult.plot()  plot resultsresult.summary()  print summary tabledf = result.to_df()  convert to DataFrameresult.save_pkl()  save to pickle file``` PrerequisitesFor running the examples in this notebook:1. Installed mvg package2. A token for API access from Viking Analytics3. The database needs to be populated with our example assets. This can be achieved by running the ["Sources and Measurement"](2-sources_and_measurements.ipynb) example.  Example flow Importing the required packages, classes and functions<jupyter_code>import os

from mvg import MVG, analysis_classes  # mvg library with python bindings to mvg-API
from mvg.analysis_classes import parse_results  # analysis classes<jupyter_output><empty_output><jupyter_text>Create a Session and test API accessNote that the `TOKEN` is used both for authorization and authentication. Thus, each unique token represents a unique user and each user has their own unique database on the Viking Analytics MultiViz Vibration service.**You need to insert your token received from Viking Analytics here:**<jupyter_code># Replace by your own Token
TOKEN = os.environ["TEST_TOKEN"] # use our own token
ENDPOINT = "https://api.beta.multiviz.com"
session = MVG(ENDPOINT, TOKEN)
session.check_version() # Check if API is accessible<jupyter_output><empty_output><jupyter_text>Running the AnalysesOnce the API session is live, we start by checking if the source u0001 we will use is available in the database:<jupyter_code>SOURCE_ID = "u0001"
session.get_source(SOURCE_ID)<jupyter_output><empty_output><jupyter_text>Requsting the AnalysisWe will now request an analysis (first two lines, uncomment one of them) and wait for the results to become available. The results as returned will be stored in a dictionary named `raw_result`. The raw results are shown in the results cell, mainly to show that they are not optimized for readability or interpretation.<jupyter_code># Specifc part : Select one of two anlysis here by un/commenting
selected_feature = "KPIDemo"
# selected_feature = "ModeId"

# Generic Part: request analysis and wait for results
analysis_request = session.request_analysis(SOURCE_ID, selected_feature)
print(f"Waiting for {analysis_request}")
session.wait_for_analyses([analysis_request["request_id"]])

# Generic Part: Displaying unparsed results
raw_result = session.get_analysis_results(analysis_request["request_id"])
raw_result<jupyter_output>Waiting for {'request_id': '6ca83f696c2c9c7852db61292b7b9c76', 'request_status': 'queued'}<jupyter_text>Showing and Browsing the results using analysis_classesTo make the results more accessible, we'll use the analysis_classes. The parse_results function will take the raw_results of (any) analysis and represent them in a python object with a number of convenience methods for summarising, plotting and exporting. For the full list of provided methods check __[the documentation](https://vikinganalytics.github.io/mvg/content/utilities_reference/analysis_classes.html)__.The parse function will automatically determine the kind (feature) of analysis based on the raw_results.Once the results are parsed, we can summarize them using the summary() method *irrespective of which analysis them stem from*. To verify this you can rerun the cell above by selecting another feature for the analysis. TimestampsThe Vibration API requires timestamps to be represented in EPOCH time. To display human interpertable timestamps a timezone and a time unit (specifying if the timestamps are seconds 's' or milliseconds 'ms' from EPOCH). This information can be given in the parse_results calls 2nd and 3rd argument). If they are left blank EPOCH times are kept.When exporting the results to a DataFrame, a column called "datetime" will be appended to show the human interpretable times.<jupyter_code># Parse
result = parse_results(raw_result, "Europe/Stockholm", "s")
# result = parse_results(raw_result) # show only raw timestamps
# Show summary
summary = result.summary()<jupyter_output>=== KPIDemo ===
request_id 6ca83f696c2c9c7852db61292b7b9c76
from 20191005-13:01.00 to 20191122-13:01.00

+-------+--------------+------------+------------+-----------------+----------------+--------------------+-------------------+--------------------+
|       |   timestamps |    rms_acc |   peak_acc |   peak2peak_acc |   variance_acc |   crest_factor_acc |   utilization_acc |   dc_component_acc |
|-------+--------------+------------+------------+-----------------+----------------+--------------------+-------------------+--------------------|
| count | 49           | 49         |   49       |       49        |     49         |          49        |                49 |         49         |
| mean  |  1.57235e+09 |  0.610976  |    2.82032 |        5.40237  |      0.376463  |           4.63947  |                 1 |         -0.120482  |
| std   |  1.2361e+06  |  0.0568944 |    0.28031 |        0.381933 |      0.0639936 |           0.329529 |                 0 |          0.0140604 |
| min  [...]<jupyter_text>PlottingFor visual representation of the results there is the 'plot' method:Please not that when plotting the results for the KPIDemo feature, one selects the KPI to be displayed by passing the parameter `"kpi"`. If this parameter is not included, the plot function will display the results of the first KPI after the timestamps, which is the RMS value.<jupyter_code>result.plot()<jupyter_output><empty_output><jupyter_text>Export results to DataFrameThe to_df() method will export results to a DataFrame. Note that the format of the DataFrame depends on the specific analysis and that not all of the results can be represented as a data frame.<jupyter_code>result.to_df()<jupyter_output><empty_output><jupyter_text>Full resultsIn case the full server results are needed in the form they were returned, we can obtain them with the results() method:<jupyter_code>result.results()<jupyter_output><empty_output><jupyter_text>Black Sheep Analysis exampleThe BlackSheep is a population analysis and has a somewhat different call signature as it requires a number of assets to be submitted to analysis.<jupyter_code># Specific signature for BlackSheep
POPULATION_SOURCES = ["u0001","u0001","u0001","u0001","u0001","u0001","u0001","u0001","u0001","u0004","u0002","u0003","u0001"]
analysis_request = session.request_population_analysis(POPULATION_SOURCES, "BlackSheep", parameters={"atypical_threshold": 0.15})

# Generic part, same as above
print(f"Waiting for {analysis_request}")
session.wait_for_analyses([analysis_request["request_id"]])
raw_result = session.get_analysis_results(analysis_request["request_id"])
raw_result<jupyter_output>Waiting for {'request_id': '023d673646aaa34407bc9cbcc4f078c8', 'request_status': 'queued'}<jupyter_text>Using the analysis classesWe use exactly the same code as above to inspect the results:<jupyter_code># Parse
blacksheep_result = analysis_classes.parse_results(raw_result, "Europe/Stockholm", "s")
# Show summary
blacksheep_result.summary()
blacksheep_result.plot()<jupyter_output>=== BlackSheep ===
request_id 023d673646aaa34407bc9cbcc4f078c8

+----+----------+------------+
|    | source   | atypical   |
|----+----------+------------|
|  0 | u0001    | True       |
|  1 | u0001    | True       |
|  2 | u0001    | True       |
|  3 | u0001    | True       |
|  4 | u0001    | True       |
|  5 | u0001    | True       |
|  6 | u0001    | True       |
|  7 | u0001    | True       |
|  8 | u0001    | True       |
|  9 | u0004    | True       |
| 10 | u0002    | True       |
| 11 | u0003    | True       |
| 12 | u0001    | True       |
+----+----------+------------+

+------------+-----+
| atypical   |   N |
|------------+-----|
| True       |  13 |
+------------+-----+<jupyter_text>SerializingFinally, we can save the object including the results to pickle. If no name is given it is saved under the name `".pkl"`.<jupyter_code>blacksheep_result.save_pkl()<jupyter_output>Saving BlackSheep object to 023d673646aaa34407bc9cbcc4f078c8.pkl
{'fraction_non_alphanumeric': 0.1219623502567028, 'fraction_numerical': 0.04449515116942385, 'mean_word_length': 3.553766233766234, 'pattern_counts': {'":': 1, '<': 40, '<?xml version=': 0, '>': 40, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '400402', 'license': 'Apache-2.0', 'n_tokens_mistral': 2734, 'n_tokens_neox': 2432, 'n_words': 881, 'path': 'docs/source/content/examples/5-analysis_classes.ipynb', 'repo_name': 'vnadhan/mvg', 'size': '8765'}