Package: fero
fero_clientferois a client-side Python library intended to help users interact withFero.QuickstartfromferoimportFero# Create a Fero client objectfero_client=Fero(username="<your username>",password="<your password>")# Get a specific analysis by its unique identifieranalysis=fero_client.get_analysis("5dfbbb63-8ad4-4638-9fdb-61e39952d3cf")# Create a pandas DataFrame with factor values for this analysisdf=pd.DataFrame([{"value":5,"value2":2}])# Make a predictionprediction=analysis.make_prediction(df)print(prediction)'''value   value2  target_low90  target_low50 target_mid target_high50  target_high900      5        2            70            75         80            88             92'''Providing CredentialsThe simplest way to provide your Fero login credentials is as arguments to theFeroobject on initialization.fero_client=Fero(username="<your username>",password="<your password>")While this is fine for interactive shells, it is not ideal for a publicly viewable script. To account for this,Feroalso supports setting theFERO_USERNAMEandFERO_PASSWORDenvironment variables or storing your username and password in a.ferofile in the home directory. This file needs to be in the the following format.FERO_USERNAME=fero_user
FERO_PASSWORD=shouldBeAGoodPasswordIf you are using theFeroclient to access an on-premises installation, both the hostname for the local Fero server can be provided withhostname="https://local.fero-site"and an internal SSL certification viaverify="path/to/ca-bundle. (Seeherefor additional details.) Verify is passed directly to the underlying Pythonrequestspackage; thus, if you desire, verification can be disabled by passingverify=False.local_client=Fero(hostname="https://fero.self.signed",verify=False)Finding a Fero AnalysisThe Fero client provides two different methods to find anAnalysis. The first isFero.get_analysiswhich takes a single unique identifier string (UUID) and attempts to look up the analysis matching this ID. The second method isFero.search_analyseswhich will return an iterator of availableAnalysisobjects. If no keyword arguments are provided, it will return all analyses you have available on Fero. Optionally,namecan be provided to filter to only analyses matching that name.ExamplesfromferoimportFerofero_client=Fero(username="<your username>",password="<your password>")# Get a specific analysisanalysis=fero_client.get_analysis("5dfbbb63-8ad4-4638-9fdb-61e39952d3cf")# Get all available analysesall_analyses=fero_client.search_analyses()# Only get "plant_A" analysesplant_A_only=fero_client.search_analyses(name="plant_A")Using an AnalysisAlong with associated properties such asnameanduuid, anAnalysisprovides a variety of methods for interacting with Fero.The first thing to call when working with an Analysis isAnalysis.has_trained_model, which checks whether the Analysis is ready to use. This will be false if the Analysis is still being configured or if there was an error during configuration.Making a simple predictionTheAnalysis.make_predictionmethod makes a prediction using the latest revision of the Analysis. This function can take either a pandasDataFramewith columns matching the expected factors or a list of dictionaries with each dictionary containing a key/value pairs for each factor. A prediction will be made for each row in theDataFrameor each dictionary in the list.The return value will either be aDataFrameor a dictionary, depending on the initial input type. These values will have the suffixes_lowX,_mid,_highXadded to each target name to indicate the prediction intervals. Specifically:target_low90corresponds to the 5% prediction level,target_low50corresponds to the 25% prediction level,target_midcorresponds to the mean prediction,target_high50corresponds to the 75% prediction level, andtarget_high90corresponds to the 95% prediction level.The naming convention indicates that:50% of the time, the corresponding measurement should fall between(target_low50, target_high50), and90% of the time, the corresponding measurement should fall between(target_low90, target_high90).Exampleraw_data=[{"value":5,"value2":2}]# Using a DataFramedf=pd.DataFrame([raw_data])prediction=analysis.make_prediction(df)print(prediction)'''value   value2  target_low90  target_low50 target_mid target_high50  target_high900      5        2            10            20         30            40             50'''# Using a list of dictsprediction=analysis.make_prediction(raw_data)print(prediction)'''[{"value": 5, "value2": 2, "target_low90": 10, "target_low": 20, "target_mid": 30, "target_high50": 40, "target_high90": 50}]'''OptimizeA more advanced usage of anAnalysisis to create an optimization which will make a prediction that satistifies a specifiedgoalwithin the context ofconstraintson other factors or targets. Currently, the Fero optimizer can be used to conduct three different types of optimizations based on anAnalysis.Example 1: Minimize a factor given constraintsFero can be used to minimizevaluewhile keepingtargetwithin a set range. The following goal and constraint configurations would need to be provided.goal={"goal":"minimize","factor":{"name":"value","min":50.0,"max":100.0}}constraints=[{"name":"target","min":100.0,"max":200}]opt=analysis.make_optimization("example_optimization",goal,constraints)By default, Fero will use the median values of fixed factors while computing the optimization. These can be overridden with custom values by passing a dictionary offactor:valuepairs as thefixed_factorsargument to the optimization function.fixed_factors={"value":10,"value2":20}opt=analysis.make_optimization("example_optimization",goal,constraints,fixed_factors)Example 2: Maximize a target KPI given constraintsAlternatively, atargetKPI can be maximized while constraining avalue. Note that the same key,factor, is used when defining the target KPI ingoal.goal={"goal":"maximize","factor":{"name":"target","min":100.0,"max":200.0}}constraints=[{"name":"value","min":50.0,"max":100.0}]opt=analysis.make_optimization("example_optimization",goal,constraints)By default, Fero will not incorporate confidence intervals while optimizing a target. The lower (5%) and upper (95%) bounds of the confidence intervals can be included during optimization by setting argumentinclude_confidence_intervalstoTrue. This will ensure that the upper or lower prediction level of the optimization result do not exceed the setmin/maxvalues fortarget. (This could have also been set toTruein the previous example.)opt=analysis.make_optimization("example_optimization",goal,constraints,fixed_factors)Example 3: Optimize a cost function over multiple factorsFero also supports the idea of a cost optimization, which will weight different factors by specified cost multipliers to find the best combination of inputs. For example, to find the minimum combined cost ofvalueandvalue2while meeting the expected values oftarget, you could do the following:goal={"goal":"minimize","type":"cost","cost_function":[{"name":"value","min":50.0,"max":100.0,"cost":5.0},{"name":"value2","min":70.0,"max":80.0.0,"cost":9.0}]}constraints=[{"name":"target","min":100.0,"max":200}]opt=analysis.make_optimization("example_cost_optimization",goal,constraints)In both cases, aPredictionobject is returned, which will provide access to the results of the optimization. By default, the result will be aDataFramebut it can also be configured to be a list of dictionaries by specifyingformat="record"inget_results.Examplegoal={"goal":"minimize","factor":{"name":"value","min":50.0,"max":100.0}}constraints=[{"name":"target","min":100.0,"max":200}]opt=analysis.make_optimization("example_optimization",goal,constraints)print(opt.get_results())'''value   value2   target (5%)   target (Mean)   target (95%)0     60       40           100             150            175'''Finding a Fero AssetThe Fero client provides two different methods to find anAsset. The first isFero.get_asset, which takes a single unique identifier string (UUID) and attempts to look up the asset matching this ID. The second method isFero.search_assets, which will return an iterator of availableAssetobjects. If no keyword arguments are provided, it will return all assets you have available on the Fero website. Optionally,namecan be provided to filter to only assets matching that name.ExamplesfromferoimportFerofero_client=Fero(username="<your username>",password="<your password>")# Get a specific assetasset=fero_client.get_asset("fd57ba36-3c5d-40f5-ae0c-d7b76ab39ee5")# Get all available assetsall_assets=fero_client.search_assets()# Get only "plant_B" assetsplant_B_only=fero_client.search_assets(name="plant_B")Using an AssetAlong with associated properties such asnameanduuid, anAssetprovides a few methods for interacting with Fero.The first thing to call when working with an asset isAsset.has_trained_model, which checks whether the Asset is ready to use. This will be false if the Asset is still being configured or if there was an error during configuration.Making a predictionTheAsset.predictmethod makes a prediction using the latest revision of the Asset. Fero computes predictions for all controllable factors and with those results, predictions for all target variables. Predictions are provided for the 5 time intervals following the end of the training dataset. (Interval size is determined during model configuration and training.) Optionally, you may callAsset.predictwith an argument specifying values for one or more of the controllable factors; Fero will predict all targets using your specified values in place of its controllable factor predictions where applicable.Examples# With no inputsprediction=asset.predict()print(prediction.columns)['mean:Factor1','p5:Factor1','p25:Factor1','p75:Factor1','p95:Factor1','mean:Factor2','p5:Factor2','p25:Factor2','p75:Factor2','p95:Factor2','mean:Target1','p5:Target1','p25:Target1','p75:Target1','p95:Target1']print(prediction)'''mean:Factor1  p5:Factor1  p25:Factor1 ... p75:Target1  p95:Target12020-12-25T00:00:00Z    7.937         7.253       7.688       ... 1.921        2.1972020-12-25T01:00:00Z    8.059         6.962       7.721       ... 1.924        2.2022020-12-25T02:00:00Z    8.193         6.754       7.692       ... 1.871        2.3182020-12-25T03:00:00Z    8.349         6.552       7.619       ... 1.830        2.3752020-12-25T04:00:00Z    8.492         6.199       7.498       ... 1.762        2.425'''# Provide specified values as a DataFramenew_factor_values=pd.DataFrame({"Factor1":[8.0,8.1,8.2,8.3,8.4]})prediction=asset.predict(new_factor_values)print(prediction.columns)['specified:Factor1','mean:Factor2','p5:Factor2','p25:Factor2','p75:Factor2','p95:Factor2','mean:Target1','p5:Target1','p25:Target1','p75:Target1','p95:Target1']print(prediction)'''specified:Factor1  mean:Factor2  p5:Factor2 ... p75:Target1  p95:Target12020-12-25T00:00:00Z    8.0                13.452        11.953     ... 1.921        2.1972020-12-25T01:00:00Z    8.1                13.119        11.762     ... 1.924        2.2022020-12-25T02:00:00Z    8.2                13.084        11.454     ... 1.871        2.3182020-12-25T03:00:00Z    8.3                13.003        11.352     ... 1.830        2.3752020-12-25T04:00:00Z    8.4                12.976        11.109     ... 1.762        2.425'''# Provide specified values as a dictionarynew_factor_values={"Factor1":[8.0,8.1,8.2,8.3,8.4]}prediction=asset.predict(new_factor_values)print(list(prediction.keys())'''['specified:Factor1', 'mean:Factor2', 'p5:Factor2', 'p25:Factor2', 'p75:Factor2','p95:Factor2', 'mean:Target1', 'p5:Target1', 'p25:Target1', 'p75:Target1', 'p95:Target1','index']'''print(prediction["mean:Factor2"])'''[13.452, 13.119, 13.084, 13.003, 12.976]'''print(prediction["index"])'''[2020-12-25T00:00:00Z, 2020-12-25T01:00:00Z, 2020-12-25T02:00:00Z, 2020-12-25T03:00:00Z, 2020-12-25T04:00:00Z]'''Fero ProcessesThe Fero client provides two different methods to find aProcess. The first isFero.get_processwhich takes a single unique identifier string (UUID) and attempts to look up the process matching this ID. The second method isFero.search_processeswhich will return an iterator of availableProcessobjects. If no keyword arguments are provided, it will return all processes you have available on Fero. Optionally,namecan be provided to filter to only processes matching that name.Processes represent data via two main underlying entities, theTagand theStage. ATagis a column of a specific measurement in the underlying data. AStageis a logical part of a process consisting of various tags and an order relative to the other stages. For example, a steel process might have first stage for melting the steel and a later stage for casting the steel, each with corresponding measurements in the form of tags.ExamplefromferoimportFerofero_client=Fero(username="<your username>",password="<your password>")# Get a single processprocess=fero_client.get_process("c6f69e96-db4d-43ed-8837-d5827cc81112")# Search processes by nameprocesses=[pforpinfero_client.search_processes(name="process X")]# Get the tags of the processtags=process.tags# Get stages of the processstages=process.stages# Get tag groups of a stagetag_groups=stages[0].tag_groupsDownloading Process DataAProcessobject can be used to download the pandasDataFramethat the process would produce for analysis. Because not all tags are generally used in a analysis, a list of desired tags is required before data can be downloaded. Additionally, a target or key performance indicator (kpi) tag can be set while requesting data. Functionally, this will limit the data returned to the stage of the kpi tag and any preceding stages. For advanced and batch processes, kpis are optional; however, they are required for continuous processes because the data is computed using the observed times of the kpi.Example# Get all data for single processprocess=fero_client.get_process("9777bae7-95af-4bea-98b9-c703ab940a05")df=process.get_data(process.tags)print(df)'''s1_factor1  s1_factor2  s2_factor1  s3_factor1  s3_factor2   s3_kpi0               0          14           7        28.5           0     49.51               1           8           5        36.0           3     53.02               2           2           3        39.5           6     52.53               3          10           8        26.5           9     56.54               4           4           6        41.5          12     67.5...           ...         ...         ...         ...         ...      ...10395       10395           4       10397        38.0       31185  52019.010396       10396           0       10396        32.5       31188  52012.510397       10397          14       10404        40.5       31191  52046.510398       10398           0       10398        25.5       31194  52015.510399       10399          14       10406        42.0       31197  52058.0[10400 rows x 6 columns]'''# Limit the process to an earlier kpidf=process.get_data(["s1_factor1","s3_kpi"],kpis=["s2_factor1"])'''dt  s2_factor1  s1_factor10    2020-03-01 00:00:00+00:00          10        <NA>1    2020-03-01 00:01:00+00:00         162        <NA>2    2020-03-01 00:02:00+00:00          12          163    2020-03-01 00:03:00+00:00          12          154    2020-03-01 00:04:00+00:00          56         162...                        ...         ...         ...1994 2020-03-02 09:14:00+00:00        2006          651995 2020-03-02 09:15:00+00:00        2007          201996 2020-03-02 09:16:00+00:00         415         1741997 2020-03-02 09:17:00+00:00        2001         1661998 2020-03-02 09:18:00+00:00           0           2[1999 rows x 3 columns]'''Downloading DataSource DataThe raw and processed data in aDataSourcecan be downloaded via the.download()method. It takes arawboolean keyword argument (defaults toFalse) that decides whether to download the raw data. It returns the local csv filename where the data was written.Exampledatasource=fero_client.get_datasource("66d2dd0f-2f16-4002-bb3b-445173eedd95")datasource.download(raw=True)'''fero-raw-ds-66d2dd0f-2f16-4002-bb3b-445173eedd95.csv'''datasource.download()'''fero-ds-66d2dd0f-2f16-4002-bb3b-445173eedd95.csv'''