*********************** Implement a new Measure *********************** Purpose of this Chapter ======================= The aim of this chapter to explain how to implement a new measure. This will be presented by implementing a simple example. Let's assume that we have several tests in a group or sequence and each test returns its results. We will implement the *weighted mean* to combine the results. Define the Metadata of the Measure ================================== .. note:: Each measure has to inherit from the abstract base class **BaseMeasure** and has to implement the abstract method **apply**. Moreover, each measure has to provide its metadata. The following metadata has to be provided by each measure: *NAME* and *DESCRIPTION*. See also: :class:`autom8qc.measures.base.BaseMeasure` .. warning:: Make sure that the class name ends with the suffix **Measure**. Other modules will check for the suffix to identify that the class is a measure. .. code-block:: python from autom8qc.core import exceptions from autom8qc.measures.base import BaseMeasure from autom8qc.qaqc.base import TestGroup class SimpleMeasure(BaseMeasure): NAME = "Weighted mean" DESCRIPTION = "Calculates the weighted mean of the given probabilities" Define the Supported Parameters =============================== Each measure has to provide the supported parameters. Therefore, you have to implement the static method **supported_parameters**. The method allows you to access the supported parameters without creating an instance of the class. If your measure doesn't need additional parameters, you don't have to implement it. In our case, we don't need additional parameters. Implement the Constructor ========================= The constructor is a method that is called when an object is created. In our case, we don't have to pass the parameters to the constructor. Note that you don’t have to check the type of the parameters since a Parameter checks the type when you set the value. If you want to implement additional checks *(e.g., the threshold must be between 0 and 1)*, you have to implement them in the constructor and raise an exception if a constraint is not satisfied. Finally, you have to call the super method **check_metadata** that checks if the instance is valid. .. warning:: Even your measure doesn't need parameters you have to implement the constructor since you have to call the super-constructor and to check the metadata of the measure. .. code-block:: python :emphasize-lines: 2 def __init__(self): super().__init__() self.check_metadata() Implement the Abstract Method ============================= Finally, we have to implement the abstract method **apply**. The method takes a **TestGroup** or **TestSequence** as a parameter and returns the combined results. To access the results *(pd.DataFrame)* of a test group or a test sequence, you have to use the method *get_results* which also checks the type of the component. If the type is invalid, the method will raises an error. .. code-block:: python :emphasize-lines: 2 def apply(self, component): results = self.get_results(component) total_weights = 0 for item in component: total_weights += item.weight results[item.name] = results[item.name] * item.weight return results.sum(axis=1) / total_weights