Exemplo n.º 1
0
def test_intern_dataset():
    """
    This dataset is internal and is mainly use to show some of the other parameter for the profile manager such as:
    - rolling_data - Which will generate all potential profile in a dataset.
    - generate_figure - Which will generate figure for all profiles automatically (may generate error if more than 25
    profiles are generated, this is a limitation of matplotlib)
    - optimize and optimizer_paramater - An experimental function that will sort the generated profile based on
    specified parameters.
    :return:
    """
    optimizer_parameter = {
        "has_limits": True,
        "validation_range": "max",
        "average.bias": "min",
        "min_loq": "min",
        "model.rsquared": "max",
    }
    data = sample_dataset.dataset("intern_test")

    profiles: ProfileManager = ProfileManager(
        "Test",
        data,
        model_to_test="Linear",
        rolling_data=True,
        optimizer_parameter=optimizer_parameter,
        allow_correction=True,
        generate_figure=True)
    profiles.make_profiles(["Linear"])
    profiles.optimize()

    profiles.profiles["Linear"][1].summary()

    assert len(profiles.sorted_profiles) == 5
    assert profiles.profiles["Linear"][1].fig is not None
    return True
Exemplo n.º 2
0
def test_feinberg_uncertainty():
    """
    Dataset from:
    Feinberg et al. (2004) New advances in method validation and measurement uncertainty aimed at improving the quality
        of chemical data. https://dx.doi.org/10.1007/s00216-004-2791-y

    This dataset is used to verify that the uncertainty calculation is in accordance with the literature.
    """
    data = sample_dataset.dataset("feinberg_uncertainty")

    profiles: ProfileManager = ProfileManager(
        "Test",
        data,
        acceptance_limit=20,
        tolerance_limit=90,
        model_to_test=["1/X^2 Weighted Linear"],
    )
    profiles.make_profiles()

    literature_composite_uncertainty: pd.Series = pd.Series({
        1: 1.399,
        2: 20.628,
        3: 36.385
    })

    literature_relative_expanded_uncertainty: pd.Series = pd.Series({
        1: 11.0,
        2: 9.4,
        3: 8.7
    })

    calculated_composite_uncertainty: pd.Series = pd.Series(
        profiles.profiles["1/X^2 Weighted Linear"][0].get_profile_parameter(
            "tolerance_std"))

    calculated_relative_expanded_uncertainty: pd.Series = pd.Series(
        profiles.profiles["1/X^2 Weighted Linear"][0].get_profile_parameter(
            "pc_uncertainty"))

    # We calculate an assertion matrice based on the percentage of error from the litterature value, for those in
    # absolute unit

    composite_uncertainty_assertion = np.abs(
        calculated_composite_uncertainty.sub(literature_composite_uncertainty).
        divide(literature_composite_uncertainty) * 100)

    # We calculate an assertion matrice based on the difference in percentage from the litterature value, for already in
    # percentage

    relative_expanded_uncertainty_assertion = np.abs(
        calculated_relative_expanded_uncertainty.sub(
            literature_relative_expanded_uncertainty))

    # We accept a maximum of 5% deviation from the literature value. This is mainly due to rounding error

    assert composite_uncertainty_assertion.ge(5).any() is not True
    assert relative_expanded_uncertainty_assertion.ge(0.5).any() is not True

    return True
Exemplo n.º 3
0
def test_inra_pyrene():
    """
    Dataset from:
    inra_pyrene: Huyez-Levrat, M et al.,Cahier technique de l'INRA - Validation des méthodes (2010), https://www6.inrae.fr/cahier_des_techniques/Les-Cahiers-parus/Les-n-Speciaux-et-les-n-Thematiques/Validation-des-methodes

    This dataset is mainly use to check if the correction factor generated is 1.2.
    The
    :return:
    """
    data = sample_dataset.dataset("inra_pyrene")

    profiles: ProfileManager = ProfileManager("Test",
                                              data,
                                              allow_correction=True)
    profiles.make_profiles(["Linear"])

    assert profiles.profiles["Linear"][0].correction_factor == 1.2
    assert profiles.profiles["Linear"][0].max_loq == 28.5
    assert np.abs(
        (4.7 - profiles.profiles["Linear"][0].min_loq) / 4.7 * 100) < 10

    return True
Exemplo n.º 4
0
def test_sfstp():
    """
    Dataset from:
    Hubert et al., Harmonization of strategies for the validation of quantitative analytical procedures. A SFSTP proposal - Part III

    This dataset is taken from the original proposal and is probably one of the most complete. It contains the data for
    the following regression models:
    - Linear through 0
    - Linear through 0 with partial dataset (up to Calibration level 4)
    - Linear
    - Weighted linear 1/X
    - log(X) - log(Y) (not available in Valexa at the moment)
    - sqrt(X) - sqrt(Y) (not available in Valexa at the moment)
    - Quadratic
    - Weighted quadratic 1/X

    Please refer to Table 5, 9, 10, 11, 12, and 13 in the original article for the reference DataFrame.

    Note: There is a ~0.1% disrepancy in the Linear models that pass through 0. This is still under investigation.
    """
    data = sample_dataset.dataset("sfstp")

    profiles: ProfileManager = ProfileManager("Test",
                                              data,
                                              acceptance_limit=20,
                                              tolerance_limit=90,
                                              model_to_test=[
                                                  "Linear through 0", "Linear",
                                                  "1/X Weighted Linear",
                                                  "Quadratic",
                                                  "1/X Weighted Quadratic"
                                              ],
                                              rolling_data_limit=4,
                                              rolling_data=False)
    profiles.make_profiles()

    litterature_reg_params: pd.DataFrame = pd.DataFrame({
        "Model": {
            0: "Linear through 0",
            1: "Linear through 0",
            2: "Linear through 0",
            3: "Linear",
            4: "Linear",
            5: "Linear",
            6: "1/X Weighted Linear",
            7: "1/X Weighted Linear",
            8: "1/X Weighted Linear",
            9: "Quadratic",
            10: "Quadratic",
            11: "Quadratic",
            12: "1/X Weighted Quadratic",
            13: "1/X Weighted Quadratic",
            14: "1/X Weighted Quadratic"
        },
        "Series": {
            0: "Serie 1",
            1: "Serie 2",
            2: "Serie 3",
            3: "Serie 1",
            4: "Serie 2",
            5: "Serie 3",
            6: "Serie 1",
            7: "Serie 2",
            8: "Serie 3",
            9: "Serie 1",
            10: "Serie 2",
            11: "Serie 3",
            12: "Serie 1",
            13: "Serie 2",
            14: "Serie 3"
        },
        "Intercept": {
            0: 0,
            1: 0,
            2: 0,
            3: -1.932e-2,
            4: -1.758e-2,
            5: -1.386e-2,
            6: -2.305e-2,
            7: -2.015e-2,
            8: -2.538e-2,
            9: -3.389e-2,
            10: -2.206e-2,
            11: -5.271e-2,
            12: -2.531e-2,
            13: -2.171e-2,
            14: -3.233e-2
        },
        "Slope": {
            0: 2.478e-3,
            1: 2.352e-3,
            2: 2.471e-3,
            3: 2.510e-3,
            4: 2.373e-3,
            5: 2.520e-3,
            6: 2.523e-3,
            7: 2.382e-3,
            8: 2.558e-3,
            9: 2.656e-3,
            10: 2.418e-3,
            11: 2.910e-3,
            12: 2.570e-3,
            13: 2.415e-3,
            14: 2.705e-3
        },
        "Quad. term.": {
            0: 0,
            1: 0,
            2: 0,
            3: 0,
            4: 0,
            5: 0,
            6: 0,
            7: 0,
            8: 0,
            9: -1.480e-7,
            10: -4.554e-8,
            11: -3.946e-7,
            12: -6.084e-8,
            13: -4.193e-8,
            14: -1.875e-7
        }
    })

    litterature_calc_x: pd.DataFrame = pd.DataFrame({
        "Series": {
            0: "Serie 1",
            1: "Serie 1",
            2: "Serie 1",
            3: "Serie 1",
            4: "Serie 1",
            5: "Serie 1",
            6: "Serie 1",
            7: "Serie 1",
            8: "Serie 1",
            9: "Serie 1",
            10: "Serie 1",
            11: "Serie 1",
            12: "Serie 1",
            13: "Serie 1",
            14: "Serie 1",
            15: "Serie 1",
            16: "Serie 2",
            17: "Serie 2",
            18: "Serie 2",
            19: "Serie 2",
            20: "Serie 2",
            21: "Serie 2",
            22: "Serie 2",
            23: "Serie 2",
            24: "Serie 2",
            25: "Serie 2",
            26: "Serie 2",
            27: "Serie 2",
            28: "Serie 2",
            29: "Serie 2",
            30: "Serie 2",
            31: "Serie 2",
            32: "Serie 3",
            33: "Serie 3",
            34: "Serie 3",
            35: "Serie 3",
            36: "Serie 3",
            37: "Serie 3",
            38: "Serie 3",
            39: "Serie 3",
            40: "Serie 3",
            41: "Serie 3",
            42: "Serie 3",
            43: "Serie 3",
            44: "Serie 3",
            45: "Serie 3",
            46: "Serie 3",
            47: "Serie 3"
        },
        "Concentration (ng/ml)": {
            0: 25.3533,
            1: 25.3533,
            2: 25.3533,
            3: 25.3533,
            4: 48.2417,
            5: 48.2417,
            6: 48.2417,
            7: 48.2417,
            8: 437.8235,
            9: 437.8235,
            10: 437.8235,
            11: 437.8235,
            12: 838.6479,
            13: 838.6479,
            14: 838.6479,
            15: 838.6479,
            16: 25.3533,
            17: 25.3533,
            18: 25.3533,
            19: 25.3533,
            20: 48.2417,
            21: 48.2417,
            22: 48.2417,
            23: 48.2417,
            24: 437.8235,
            25: 437.8235,
            26: 437.8235,
            27: 437.8235,
            28: 838.6479,
            29: 838.6479,
            30: 838.6479,
            31: 838.6479,
            32: 25.3533,
            33: 25.3533,
            34: 25.3533,
            35: 25.3533,
            36: 48.2417,
            37: 48.2417,
            38: 48.2417,
            39: 48.2417,
            40: 437.8235,
            41: 437.8235,
            42: 437.8235,
            43: 437.8235,
            44: 838.6479,
            45: 838.6479,
            46: 838.6479,
            47: 838.6479
        },
        "Linear through 0": {
            0: 17.71,
            1: 19.69,
            2: 19.37,
            3: 19.53,
            4: 38.29,
            5: 37.41,
            6: 35.79,
            7: 40.96,
            8: 398.4,
            9: 409,
            10: 415.1,
            11: 410.5,
            12: 815.9,
            13: 803,
            14: 844.8,
            15: 814.7,
            16: 15.78,
            17: 17.95,
            18: 19.6,
            19: 19.05,
            20: 39.21,
            21: 38.95,
            22: 36.32,
            23: 39.04,
            24: 413.3,
            25: 438.9,
            26: 439.8,
            27: 438.8,
            28: 818.7,
            29: 862.6,
            30: 855.9,
            31: 862.1,
            32: 17.97,
            33: 18.5,
            34: 20.32,
            35: 19.23,
            36: 38.69,
            37: 41.41,
            38: 40.76,
            39: 44.2,
            40: 420.6,
            41: 450.6,
            42: 462.2,
            43: 435.1,
            44: 861,
            45: 895.6,
            46: 918.7,
            47: 912.5
        },
        "Linear": {
            0: 25.19,
            1: 27.14,
            2: 26.82,
            3: 26.98,
            4: 45.5,
            5: 44.63,
            6: 43.03,
            7: 48.13,
            8: 401,
            9: 411.5,
            10: 417.6,
            11: 413,
            12: 813.3,
            13: 800.5,
            14: 841.8,
            15: 812,
            16: 23.04,
            17: 25.19,
            18: 26.83,
            19: 26.28,
            20: 46.26,
            21: 46,
            22: 43.39,
            23: 46.09,
            24: 416.9,
            25: 442.3,
            26: 443.2,
            27: 442.2,
            28: 818.6,
            29: 862.1,
            30: 855.5,
            31: 861.6,
            32: 23.12,
            33: 23.64,
            34: 25.42,
            35: 24.35,
            36: 43.44,
            37: 46.1,
            38: 45.46,
            39: 48.83,
            40: 417.9,
            41: 447.2,
            42: 458.6,
            43: 432.1,
            44: 849.6,
            45: 883.5,
            46: 906.2,
            47: 900.2
        },
        "1/X Weighted Linear": {
            0: 26.54,
            1: 28.48,
            2: 28.17,
            3: 28.33,
            4: 46.76,
            5: 45.89,
            6: 44.3,
            7: 49.38,
            8: 400.5,
            9: 411,
            10: 417,
            11: 412.4,
            12: 810.7,
            13: 798.1,
            14: 839.1,
            15: 809.5,
            16: 24.04,
            17: 26.18,
            18: 27.82,
            19: 27.27,
            20: 47.17,
            21: 46.92,
            22: 44.32,
            23: 47,
            24: 416.5,
            25: 441.8,
            26: 442.7,
            27: 441.7,
            28: 816.7,
            29: 860.1,
            30: 853.5,
            31: 859.6,
            32: 27.27,
            33: 27.78,
            34: 29.54,
            35: 28.48,
            36: 47.28,
            37: 49.9,
            38: 49.28,
            39: 52.6,
            40: 416.1,
            41: 445,
            42: 456.2,
            43: 430.1,
            44: 841.3,
            45: 874.8,
            46: 897.1,
            47: 891.1
        },
        "Quadratic": {
            0: 29.33,
            1: 31.18,
            2: 30.88,
            3: 31.03,
            4: 48.62,
            5: 47.78,
            6: 46.27,
            7: 51.11,
            8: 393,
            9: 403.4,
            10: 409.4,
            11: 404.9,
            12: 810.6,
            13: 797.4,
            14: 840.3,
            15: 809.3,
            16: 24.48,
            17: 26.59,
            18: 28.2,
            19: 27.66,
            20: 47.29,
            21: 47.04,
            22: 44.48,
            23: 47.13,
            24: 414.2,
            25: 439.6,
            26: 440.4,
            27: 439.5,
            28: 817.8,
            29: 861.9,
            30: 855.2,
            31: 861.4,
            32: 33.52,
            33: 33.98,
            34: 35.54,
            35: 34.6,
            36: 51.32,
            37: 53.66,
            38: 53.1,
            39: 56.07,
            40: 396.5,
            41: 425.2,
            42: 436.3,
            43: 410.4,
            44: 846.2,
            45: 884.6,
            46: 910.6,
            47: 903.6
        },
        "1/X Weighted Quadratic": {
            0: 26.94,
            1: 28.85,
            2: 28.54,
            3: 28.7,
            4: 46.82,
            5: 45.96,
            6: 44.4,
            7: 49.4,
            8: 397.7,
            9: 408.2,
            10: 414.2,
            11: 409.6,
            12: 812.2,
            13: 799.3,
            14: 841.2,
            15: 810.9,
            16: 24.37,
            17: 26.48,
            18: 28.1,
            19: 27.56,
            20: 47.21,
            21: 46.96,
            22: 44.39,
            23: 47.05,
            24: 414.4,
            25: 439.8,
            26: 440.7,
            27: 439.7,
            28: 817.9,
            29: 861.9,
            30: 855.2,
            31: 861.4,
            32: 28.42,
            33: 28.9,
            34: 30.57,
            35: 29.57,
            36: 47.44,
            37: 49.94,
            38: 49.34,
            39: 52.5,
            40: 407.6,
            41: 436.6,
            42: 447.9,
            43: 421.7,
            44: 848.1,
            45: 884,
            46: 908.1,
            47: 901.7
        },
    })

    litterature_true_prec_abs: pd.DataFrame = pd.DataFrame({
        "Model": {
            0: "Linear through 0",
            1: "Linear through 0",
            2: "Linear through 0",
            3: "Linear through 0",
            4: "Linear",
            5: "Linear",
            6: "Linear",
            7: "Linear",
            8: "1/X Weighted Linear",
            9: "1/X Weighted Linear",
            10: "1/X Weighted Linear",
            11: "1/X Weighted Linear",
            12: "Quadratic",
            13: "Quadratic",
            14: "Quadratic",
            15: "Quadratic",
            16: "1/X Weighted Quadratic",
            17: "1/X Weighted Quadratic",
            18: "1/X Weighted Quadratic",
            19: "1/X Weighted Quadratic"
        },
        "Introduced concentration (ng/ml)": {
            0: 25.35,
            1: 48.24,
            2: 437.8,
            3: 838.6,
            4: 25.35,
            5: 48.24,
            6: 437.8,
            7: 838.6,
            8: 25.35,
            9: 48.24,
            10: 437.8,
            11: 838.6,
            12: 25.35,
            13: 48.24,
            14: 437.8,
            15: 838.6,
            16: 25.35,
            17: 48.24,
            18: 437.8,
            19: 838.6
        },
        "Mean calculated concentration (ng/ml)": {
            0: 18.72,
            1: 39.25,
            2: 427.7,
            3: 855.5,
            4: 25.33,
            5: 45.57,
            6: 428.6,
            7: 850.4,
            8: 27.49,
            9: 47.57,
            10: 427.6,
            11: 846,
            12: 30.58,
            13: 49.49,
            14: 417.7,
            15: 849.9,
            16: 28.08,
            17: 47.62,
            18: 423.2,
            19: 850.2
        },
        "Bias (ng/ml)": {
            0: -6.629,
            1: -8.99,
            2: -10.13,
            3: 16.82,
            4: -2.02e-2,
            5: -2.669,
            6: -9.192,
            7: 11.77,
            8: 2.138,
            9: -0.6752,
            10: -10.24,
            11: 7.325,
            12: 5.23,
            13: 1.247,
            14: -20.09,
            15: 11.25,
            16: 2.729,
            17: -0.6233,
            18: -14.65,
            19: 11.51
        },
        "Repeatability standard deviation (ng/ml)": {
            0: 1.229,
            1: 1.978,
            2: 13.5,
            3: 21.81,
            4: 1.242,
            5: 1.785,
            6: 13.29,
            7: 21.49,
            8: 1.234,
            9: 1.93,
            10: 13.15,
            11: 21.29,
            12: 1.184,
            13: 1.802,
            14: 13.07,
            15: 23.17,
            16: 1.207,
            17: 1.874,
            18: 13.19,
            19: 22.26
        },
        "Between series standard deviation (ng/ml)": {
            0: 0,
            1: 1.442,
            2: 16.13,
            3: 37.43,
            4: 1.026,
            5: 0.,
            6: 14.04,
            7: 32.26,
            8: 0.8223,
            9: 1.646,
            10: 13.54,
            11: 29.01,
            12: 3.792,
            13: 3.527,
            14: 13.93,
            15: 34.02,
            16: 1.239,
            17: 1.651,
            18: 12.22,
            19: 32.98
        },
        "Intermediate precision standard deviation (ng/ml)": {
            0: 1.229,
            1: 2.447,
            2: 21.03,
            3: 43.32,
            4: 1.61,
            5: 1.785,
            6: 19.33,
            7: 38.76,
            8: 1.483,
            9: 2.537,
            10: 18.87,
            11: 35.98,
            12: 3.973,
            13: 3.961,
            14: 19.1,
            15: 41.16,
            16: 1.73,
            17: 2.498,
            18: 17.98,
            19: 39.79
        },
    })

    litterature_true_prec_per: pd.DataFrame = pd.DataFrame({
        "Model": {
            0: "Linear through 0",
            1: "Linear through 0",
            2: "Linear through 0",
            3: "Linear through 0",
            4: "Linear",
            5: "Linear",
            6: "Linear",
            7: "Linear",
            8: "1/X Weighted Linear",
            9: "1/X Weighted Linear",
            10: "1/X Weighted Linear",
            11: "1/X Weighted Linear",
            12: "Quadratic",
            13: "Quadratic",
            14: "Quadratic",
            15: "Quadratic",
            16: "1/X Weighted Quadratic",
            17: "1/X Weighted Quadratic",
            18: "1/X Weighted Quadratic",
            19: "1/X Weighted Quadratic"
        },
        "Relative bias (%)": {
            0: -26.15,
            1: -18.64,
            2: -2.313,
            3: 2.005,
            4: -7.95e-2,
            5: -5.533,
            6: -2.099,
            7: 1.404,
            8: 8.434,
            9: -1.4,
            10: -2.338,
            11: 0.8735,
            12: 20.63,
            13: 2.586,
            14: -4.587,
            15: 1.341,
            16: 10.76,
            17: -1.292,
            18: -3.345,
            19: 1.373
        },
        "Recovery (%)": {
            0: 73.85,
            1: 81.36,
            2: 97.69,
            3: 102,
            4: 99.92,
            5: 94.47,
            6: 97.9,
            7: 101.4,
            8: 108.4,
            9: 98.6,
            10: 97.66,
            11: 100.9,
            12: 120.6,
            13: 102.6,
            14: 95.41,
            15: 101.3,
            16: 110.8,
            17: 98.71,
            18: 96.65,
            19: 101.4
        },
        "CV repeatability (%)": {
            0: 4.846,
            1: 4.1,
            2: 3.083,
            3: 2.601,
            4: 4.897,
            5: 3.701,
            6: 3.035,
            7: 2.563,
            8: 4.866,
            9: 4.001,
            10: 3.003,
            11: 2.539,
            12: 4.672,
            13: 3.736,
            14: 2.986,
            15: 2.763,
            16: 4.762,
            17: 3.885,
            18: 3.013,
            19: 2.654
        },
        "CV intermediate precision (%)": {
            0: 4.846,
            1: 5.073,
            2: 4.803,
            3: 5.166,
            4: 6.352,
            5: 3.701,
            6: 4.414,
            7: 4.622,
            8: 5.848,
            9: 5.259,
            10: 4.31,
            11: 4.291,
            12: 15.67,
            13: 8.211,
            14: 4.363,
            15: 4.908,
            16: 6.824,
            17: 5.177,
            18: 4.107,
            19: 4.744
        }
    })

    litterature_rel_acc: pd.DataFrame = pd.DataFrame({
        "Series": {
            0: "Serie 1",
            1: "Serie 1",
            2: "Serie 1",
            3: "Serie 1",
            4: "Serie 1",
            5: "Serie 1",
            6: "Serie 1",
            7: "Serie 1",
            8: "Serie 1",
            9: "Serie 1",
            10: "Serie 1",
            11: "Serie 1",
            12: "Serie 1",
            13: "Serie 1",
            14: "Serie 1",
            15: "Serie 1",
            16: "Serie 2",
            17: "Serie 2",
            18: "Serie 2",
            19: "Serie 2",
            20: "Serie 2",
            21: "Serie 2",
            22: "Serie 2",
            23: "Serie 2",
            24: "Serie 2",
            25: "Serie 2",
            26: "Serie 2",
            27: "Serie 2",
            28: "Serie 2",
            29: "Serie 2",
            30: "Serie 2",
            31: "Serie 2",
            32: "Serie 3",
            33: "Serie 3",
            34: "Serie 3",
            35: "Serie 3",
            36: "Serie 3",
            37: "Serie 3",
            38: "Serie 3",
            39: "Serie 3",
            40: "Serie 3",
            41: "Serie 3",
            42: "Serie 3",
            43: "Serie 3",
            44: "Serie 3",
            45: "Serie 3",
            46: "Serie 3",
            47: "Serie 3"
        },
        "Concentration (ng/ml)": {
            0: 25.3533,
            1: 25.3533,
            2: 25.3533,
            3: 25.3533,
            4: 48.2417,
            5: 48.2417,
            6: 48.2417,
            7: 48.2417,
            8: 437.8235,
            9: 437.8235,
            10: 437.8235,
            11: 437.8235,
            12: 838.6479,
            13: 838.6479,
            14: 838.6479,
            15: 838.6479,
            16: 25.3533,
            17: 25.3533,
            18: 25.3533,
            19: 25.3533,
            20: 48.2417,
            21: 48.2417,
            22: 48.2417,
            23: 48.2417,
            24: 437.8235,
            25: 437.8235,
            26: 437.8235,
            27: 437.8235,
            28: 838.6479,
            29: 838.6479,
            30: 838.6479,
            31: 838.6479,
            32: 25.3533,
            33: 25.3533,
            34: 25.3533,
            35: 25.3533,
            36: 48.2417,
            37: 48.2417,
            38: 48.2417,
            39: 48.2417,
            40: 437.8235,
            41: 437.8235,
            42: 437.8235,
            43: 437.8235,
            44: 838.6479,
            45: 838.6479,
            46: 838.6479,
            47: 838.6479
        },
        "Linear through 0": {
            0: -30.15,
            1: -22.34,
            2: -23.60,
            3: -22.97,
            4: -20.63,
            5: -22.45,
            6: -25.81,
            7: -15.09,
            8: -9.00,
            9: -6.58,
            10: -5.19,
            11: -6.24,
            12: -2.71,
            13: -4.25,
            14: 0.73,
            15: -2.86,
            16: -37.76,
            17: -29.20,
            18: -22.69,
            19: -24.86,
            20: -18.72,
            21: -19.26,
            22: -24.71,
            23: -19.07,
            24: -5.60,
            25: 0.25,
            26: 0.45,
            27: 0.22,
            28: -2.38,
            29: 2.86,
            30: 2.06,
            31: 2.80,
            32: -29.12,
            33: -27.03,
            34: -19.85,
            35: -24.15,
            36: -19.80,
            37: -14.16,
            38: -15.51,
            39: -8.38,
            40: -3.93,
            41: 2.92,
            42: 5.57,
            43: -0.62,
            44: 2.67,
            45: 6.79,
            46: 9.55,
            47: 8.81
        },
        "Linear": {
            0: -0.64,
            1: 7.05,
            2: 5.79,
            3: 6.42,
            4: -5.68,
            5: -7.49,
            6: -10.80,
            7: -0.23,
            8: -8.41,
            9: -6.01,
            10: -4.62,
            11: -5.67,
            12: -3.02,
            13: -4.55,
            14: 0.38,
            15: -3.18,
            16: -9.12,
            17: -0.64,
            18: 5.82,
            19: 3.66,
            20: -4.11,
            21: -4.65,
            22: -10.06,
            23: -4.46,
            24: -4.78,
            25: 1.02,
            26: 1.23,
            27: 1.00,
            28: -2.39,
            29: 2.80,
            30: 2.01,
            31: 2.74,
            32: -8.81,
            33: -6.76,
            34: 0.26,
            35: -3.96,
            36: -9.95,
            37: -4.44,
            38: -5.77,
            39: 1.22,
            40: -4.55,
            41: 2.14,
            42: 4.75,
            43: -1.31,
            44: 1.31,
            45: 5.35,
            46: 8.05,
            47: 7.34
        },
        "1/X Weighted Linear": {
            0: 4.68,
            1: 12.33,
            2: 11.11,
            3: 11.74,
            4: -3.07,
            5: -4.87,
            6: -8.17,
            7: 2.36,
            8: -8.52,
            9: -6.13,
            10: -4.76,
            11: -5.81,
            12: -3.33,
            13: -4.83,
            14: 0.05,
            15: -3.48,
            16: -5.18,
            17: 3.26,
            18: 9.73,
            19: 7.56,
            20: -2.22,
            21: -2.74,
            22: -8.13,
            23: -2.57,
            24: -4.87,
            25: 0.91,
            26: 1.11,
            27: 0.89,
            28: -2.62,
            29: 2.56,
            30: 1.77,
            31: 2.50,
            32: 7.56,
            33: 9.57,
            34: 16.51,
            35: 12.33,
            36: -1.99,
            37: 3.44,
            38: 2.15,
            39: 9.03,
            40: -4.96,
            41: 1.64,
            42: 4.20,
            43: -1.76,
            44: 0.32,
            45: 4.31,
            46: 6.97,
            47: 6.25
        },
        "Quadratic": {
            0: 15.69,
            1: 22.98,
            2: 21.80,
            3: 22.39,
            4: 0.78,
            5: -0.96,
            6: -4.09,
            7: 5.95,
            8: -10.24,
            9: -7.86,
            10: -6.49,
            11: -7.52,
            12: -3.34,
            13: -4.92,
            14: 0.20,
            15: -3.50,
            16: -3.44,
            17: 4.88,
            18: 11.23,
            19: 9.10,
            20: -1.97,
            21: -2.49,
            22: -7.80,
            23: -2.30,
            24: -5.40,
            25: 0.41,
            26: 0.59,
            27: 0.38,
            28: -2.49,
            29: 2.77,
            30: 1.97,
            31: 2.71,
            32: 32.21,
            33: 34.03,
            34: 40.18,
            35: 36.47,
            36: 6.38,
            37: 11.23,
            38: 10.07,
            39: 16.23,
            40: -9.44,
            41: -2.88,
            42: -0.35,
            43: -6.26,
            44: 0.90,
            45: 5.48,
            46: 8.58,
            47: 7.74
        },
        "1/X Weighted Quadratic": {
            0: 6.26,
            1: 13.79,
            2: 12.57,
            3: 13.20,
            4: -2.95,
            5: -4.73,
            6: -7.96,
            7: 2.40,
            8: -9.16,
            9: -6.77,
            10: -5.40,
            11: -6.45,
            12: -3.15,
            13: -4.69,
            14: 0.30,
            15: -3.31,
            16: -3.88,
            17: 4.44,
            18: 10.83,
            19: 8.70,
            20: -2.14,
            21: -2.66,
            22: -7.98,
            23: -2.47,
            24: -5.35,
            25: 0.45,
            26: 0.66,
            27: 0.43,
            28: -2.47,
            29: 2.77,
            30: 1.97,
            31: 2.71,
            32: 12.10,
            33: 13.99,
            34: 20.58,
            35: 16.63,
            36: -1.66,
            37: 3.52,
            38: 2.28,
            39: 8.83,
            40: -6.90,
            41: -0.28,
            42: 2.30,
            43: -3.68,
            44: 1.13,
            45: 5.41,
            46: 8.28,
            47: 7.52
        },
    })

    litterature_p_t_te_me_abs: pd.DataFrame = pd.DataFrame({
        "Model": {
            0: "Linear through 0",
            1: "Linear through 0",
            2: "Linear through 0",
            3: "Linear through 0",
            4: "Linear",
            5: "Linear",
            6: "Linear",
            7: "Linear",
            8: "1/X Weighted Linear",
            9: "1/X Weighted Linear",
            10: "1/X Weighted Linear",
            11: "1/X Weighted Linear",
            12: "Quadratic",
            13: "Quadratic",
            14: "Quadratic",
            15: "Quadratic",
            16: "1/X Weighted Quadratic",
            17: "1/X Weighted Quadratic",
            18: "1/X Weighted Quadratic",
            19: "1/X Weighted Quadratic"
        },
        "Concentration (ng/ml)": {
            0: 25.35,
            1: 48.24,
            2: 437.8,
            3: 838.6,
            4: 25.35,
            5: 48.24,
            6: 437.8,
            7: 838.6,
            8: 25.35,
            9: 48.24,
            10: 437.8,
            11: 838.6,
            12: 25.35,
            13: 48.24,
            14: 437.8,
            15: 838.6,
            16: 25.35,
            17: 48.24,
            18: 437.8,
            19: 838.6
        },
        "Intermediate precision (ng/ml)": {
            0: 1.229,
            1: 2.447,
            2: 21.03,
            3: 43.32,
            4: 1.61,
            5: 1.785,
            6: 19.33,
            7: 38.76,
            8: 1.483,
            9: 2.537,
            10: 18.87,
            11: 35.98,
            12: 3.973,
            13: 3.961,
            14: 19.1,
            15: 41.16,
            16: 1.73,
            17: 2.498,
            18: 17.98,
            19: 39.79
        },
        "Trueness (ng/ml)": {
            0: -6.629,
            1: -8.99,
            2: -10.13,
            3: 16.82,
            4: -2.02E-02,
            5: -2.669,
            6: -9.192,
            7: 11.77,
            8: 2.138,
            9: -0.6752,
            10: -10.24,
            11: 7.325,
            12: 5.23,
            13: 1.247,
            14: -20.09,
            15: 11.25,
            16: 2.729,
            17: -0.6233,
            18: -14.65,
            19: 11.51
        },
        "Absolute total error (ng/ml)": {
            0: 7.858,
            1: 11.437,
            2: 31.16,
            3: 60.14,
            4: 1.63016,
            5: 4.454,
            6: 28.522,
            7: 50.53,
            8: 3.621,
            9: 3.2122,
            10: 29.11,
            11: 43.305,
            12: 9.203,
            13: 5.208,
            14: 39.19,
            15: 52.41,
            16: 4.459,
            17: 3.1213,
            18: 32.63,
            19: 51.3
        },
    })

    litterature_p_t_te_me_per: pd.DataFrame = pd.DataFrame({
        "Model": {
            0: "Linear through 0",
            1: "Linear through 0",
            2: "Linear through 0",
            3: "Linear through 0",
            4: "Linear",
            5: "Linear",
            6: "Linear",
            7: "Linear",
            8: "1/X Weighted Linear",
            9: "1/X Weighted Linear",
            10: "1/X Weighted Linear",
            11: "1/X Weighted Linear",
            12: "Quadratic",
            13: "Quadratic",
            14: "Quadratic",
            15: "Quadratic",
            16: "1/X Weighted Quadratic",
            17: "1/X Weighted Quadratic",
            18: "1/X Weighted Quadratic",
            19: "1/X Weighted Quadratic"
        },
        "Relative total error (%)": {
            0: 31.0,
            1: 23.7,
            2: 7.1,
            3: 7.2,
            4: 6.4,
            5: 9.2,
            6: 6.5,
            7: 6.0,
            8: 14.3,
            9: 6.7,
            10: 6.6,
            11: 5.2,
            12: 36.3,
            13: 10.8,
            14: 9.0,
            15: 6.2,
            16: 17.6,
            17: 6.5,
            18: 7.5,
            19: 6.1
        }
    })

    litterature_tol_interval_abs: pd.DataFrame = pd.DataFrame({
        "Model": {
            0: "Linear through 0",
            1: "Linear through 0",
            2: "Linear through 0",
            3: "Linear through 0",
            4: "Linear",
            5: "Linear",
            6: "Linear",
            7: "Linear",
            8: "1/X Weighted Linear",
            9: "1/X Weighted Linear",
            10: "1/X Weighted Linear",
            11: "1/X Weighted Linear",
            12: "Quadratic",
            13: "Quadratic",
            14: "Quadratic",
            15: "Quadratic",
            16: "1/X Weighted Quadratic",
            17: "1/X Weighted Quadratic",
            18: "1/X Weighted Quadratic",
            19: "1/X Weighted Quadratic"
        },
        "Introduced concentration (ng/ml)": {
            0: 25.35,
            1: 48.24,
            2: 437.8,
            3: 838.6,
            4: 25.35,
            5: 48.24,
            6: 437.8,
            7: 838.6,
            8: 25.35,
            9: 48.24,
            10: 437.8,
            11: 838.6,
            12: 25.35,
            13: 48.24,
            14: 437.8,
            15: 838.6,
            16: 25.35,
            17: 48.24,
            18: 437.8,
            19: 838.6
        },
        "Absolute tolerance limits (ng/ml) low": {
            0: 16.42,
            1: 34.16,
            2: 378.0,
            3: 740.8,
            4: 21.89,
            5: 42.23,
            6: 384.6,
            7: 752.0,
            8: 24.46,
            9: 42.11,
            10: 384.9,
            11: 757.4,
            12: 18.39,
            13: 38.59,
            14: 374.1,
            15: 746.1,
            16: 24.17,
            17: 42.20,
            18: 383.7,
            19: 749.5
        },
        "Absolute tolerance limits (ng/ml) high": {
            0: 21.03,
            1: 44.34,
            2: 477.4,
            3: 970.2,
            4: 28.77,
            5: 48.92,
            6: 472.6,
            7: 948.9,
            8: 30.53,
            9: 53.03,
            10: 470.2,
            11: 934.6,
            12: 42.78,
            13: 60.39,
            14: 461.3,
            15: 953.7,
            16: 31.99,
            17: 53.03,
            18: 462.7,
            19: 950.8
        },
    })

    litterature_tol_interval_per: pd.DataFrame = pd.DataFrame({
        "Model": {
            0: "Linear through 0",
            1: "Linear through 0",
            2: "Linear through 0",
            3: "Linear through 0",
            4: "Linear",
            5: "Linear",
            6: "Linear",
            7: "Linear",
            8: "1/X Weighted Linear",
            9: "1/X Weighted Linear",
            10: "1/X Weighted Linear",
            11: "1/X Weighted Linear",
            12: "Quadratic",
            13: "Quadratic",
            14: "Quadratic",
            15: "Quadratic",
            16: "1/X Weighted Quadratic",
            17: "1/X Weighted Quadratic",
            18: "1/X Weighted Quadratic",
            19: "1/X Weighted Quadratic"
        },
        "Relative tolerance limits (%) low": {
            0: -35.23,
            1: -29.19,
            2: -13.66,
            3: -11.67,
            4: -13.64,
            5: -12.47,
            6: -12.15,
            7: -10.33,
            8: -3.534,
            9: -12.72,
            10: -12.08,
            11: -9.692,
            12: -27.47,
            13: -20.00,
            14: -14.55,
            15: -11.04,
            16: -4.648,
            17: -12.52,
            18: -12.37,
            19: -10.63
        },
        "Relative tolerance limits (%) high": {
            0: -17.06,
            1: -8.084,
            2: 9.037,
            3: 15.68,
            4: 13.49,
            5: 1.405,
            6: 7.953,
            7: 13.14,
            8: 20.40,
            9: 9.916,
            10: 7.404,
            11: 11.44,
            12: 68.72,
            13: 25.18,
            14: 5.373,
            15: 13.72,
            16: 26.18,
            17: 9.935,
            18: 5.675,
            19: 13.37
        },
    })

    reg_params_dict: dict = {
        "Model_str": [],
        "Series_str": [],
        "Intercept": [],
        "Slope": [],
        "Quad. term.": []
    }

    true_prec_dict_abs: dict = {
        "Model_str": [],
        "Introduced concentration (ng/ml)": [],
        "Mean calculated concentration (ng/ml)": [],
        "Bias (ng/ml)": [],
        "Repeatability standard deviation (ng/ml)": [],
        "Between series standard deviation (ng/ml)": [],
        "Intermediate precision standard deviation (ng/ml)": [],
    }

    true_prec_dict_per: dict = {
        "Model_str": [],
        "Relative bias (%)": [],
        "Recovery (%)": [],
        "CV repeatability (%)": [],
        "CV intermediate precision (%)": []
    }

    p_t_te_me_dict_abs: dict = {
        "Model_str": [],
        "Concentration (ng/ml)": [],
        "Intermediate precision (ng/ml)": [],
        "Trueness (ng/ml)": [],
        "Absolute total error (ng/ml)": [],
    }

    p_t_te_me_dict_per: dict = {
        "Model_str": [],
        "Relative total error (%)": [],
    }

    tol_interval_dict_abs: dict = {
        "Model_str": [],
        "Introduced concentration (ng/ml)": [],
        "Absolute tolerance limits (ng/ml) low": [],
        "Absolute tolerance limits (ng/ml) high": [],
    }

    tol_interval_dict_per: dict = {
        "Model_str": [],
        "Relative tolerance limits (%) low": [],
        "Relative tolerance limits (%) high": [],
    }

    calc_x_dataframe: pd.DataFrame = profiles.data_objects[0].validation_data[[
        "Serie", "Level", "x"
    ]]
    rel_acc_dataframe: pd.DataFrame = profiles.data_objects[0].validation_data[
        ["Serie", "Level", "x"]]

    for key, value in profiles.profiles.items():
        calc_x_dataframe[key] = np.array(
            [np.float32(num) for num in value[0].model.data_x_calc])
        rel_acc_dataframe[key] = ((value[0].model.validation_data["x_calc"] -
                                   value[0].model.validation_data["x"]) /
                                  value[0].model.validation_data["x"] *
                                  100).astype(float)

        for serie, serie_value in value[0].model.fit.items():
            reg_params_dict["Model_str"].append(key)
            reg_params_dict["Series_str"].append("Serie " + str(serie))
            if "Intercept" in serie_value.params:
                reg_params_dict["Intercept"].append(
                    serie_value.params["Intercept"])
            else:
                reg_params_dict["Intercept"].append(0)
            reg_params_dict["Slope"].append(serie_value.params["x"])
            if "I(x ** 2)" in serie_value.params:
                reg_params_dict["Quad. term."].append(
                    serie_value.params["I(x ** 2)"])
            else:
                reg_params_dict["Quad. term."].append(0)

        for level, level_value in value[0].profile_levels.items():

            true_prec_dict_abs["Model_str"].append(key)
            true_prec_dict_per["Model_str"].append(key)
            true_prec_dict_abs["Introduced concentration (ng/ml)"].append(
                level_value.introduced_concentration)
            true_prec_dict_abs["Mean calculated concentration (ng/ml)"].append(
                level_value.calculated_concentration)
            true_prec_dict_abs["Bias (ng/ml)"].append(level_value.bias)
            true_prec_dict_per["Relative bias (%)"].append(
                level_value.relative_bias)
            true_prec_dict_per["Recovery (%)"].append(level_value.recovery)
            true_prec_dict_abs[
                "Repeatability standard deviation (ng/ml)"].append(
                    level_value.repeatability_std)
            true_prec_dict_abs[
                "Between series standard deviation (ng/ml)"].append(
                    level_value.inter_series_std)
            true_prec_dict_abs[
                "Intermediate precision standard deviation (ng/ml)"].append(
                    level_value.intermediate_precision_std)
            true_prec_dict_per["CV repeatability (%)"].append(
                level_value.repeatability_cv)
            true_prec_dict_per["CV intermediate precision (%)"].append(
                level_value.intermediate_precision_cv)

            p_t_te_me_dict_abs["Model_str"].append(key)
            p_t_te_me_dict_per["Model_str"].append(key)
            p_t_te_me_dict_abs["Concentration (ng/ml)"].append(
                level_value.introduced_concentration)
            p_t_te_me_dict_abs["Intermediate precision (ng/ml)"].append(
                level_value.intermediate_precision_std)
            p_t_te_me_dict_abs["Trueness (ng/ml)"].append(level_value.bias)
            p_t_te_me_dict_abs["Absolute total error (ng/ml)"].append(
                level_value.total_error_abs)
            p_t_te_me_dict_per["Relative total error (%)"].append(
                level_value.total_error_rel)

            tol_interval_dict_abs["Model_str"].append(key)
            tol_interval_dict_per["Model_str"].append(key)
            tol_interval_dict_abs["Introduced concentration (ng/ml)"].append(
                level_value.introduced_concentration)
            tol_interval_dict_abs[
                "Absolute tolerance limits (ng/ml) low"].append(
                    level_value.abs_tolerance[0])
            tol_interval_dict_abs[
                "Absolute tolerance limits (ng/ml) high"].append(
                    level_value.abs_tolerance[1])
            tol_interval_dict_per["Relative tolerance limits (%) low"].append(
                level_value.rel_tolerance[0] - 100)
            tol_interval_dict_per["Relative tolerance limits (%) high"].append(
                level_value.rel_tolerance[1] - 100)

    reg_params_dataframe: pd.DataFrame = pd.DataFrame(reg_params_dict)
    true_prec_dataframe_abs: pd.DataFrame = pd.DataFrame(true_prec_dict_abs)
    true_prec_dataframe_per: pd.DataFrame = pd.DataFrame(true_prec_dict_per)
    p_t_te_me_dataframe_abs: pd.DataFrame = pd.DataFrame(p_t_te_me_dict_abs)
    p_t_te_me_dataframe_per: pd.DataFrame = pd.DataFrame(p_t_te_me_dict_per)
    tol_interval_dataframe_abs: pd.DataFrame = pd.DataFrame(
        tol_interval_dict_abs)
    tol_interval_dataframe_per: pd.DataFrame = pd.DataFrame(
        tol_interval_dict_per)

    # We calculate an assertion matrice based on the percentage of error from the litterature value, for those in
    # absolute unit

    reg_params_assertion = np.abs(
        reg_params_dataframe.sub(litterature_reg_params).divide(
            litterature_reg_params) * 100)
    x_calc_assertion = np.abs(
        calc_x_dataframe.sub(litterature_calc_x).divide(litterature_calc_x) *
        100)
    true_prec_assertion_abs = np.abs(
        true_prec_dataframe_abs.sub(litterature_true_prec_abs).divide(
            litterature_true_prec_abs) * 100)
    p_t_te_me_assertion_abs = np.abs(
        p_t_te_me_dataframe_abs.sub(litterature_p_t_te_me_abs).divide(
            litterature_p_t_te_me_abs) * 100)
    tol_interval_assertion_abs = np.abs(
        tol_interval_dataframe_abs.sub(litterature_tol_interval_abs).divide(
            litterature_tol_interval_abs) * 100)

    # We calculate an assertion matrice based on the difference in percentage from the litterature value, for already in
    # percentage

    rel_acc_assertion = np.abs(rel_acc_dataframe.sub(litterature_rel_acc))
    true_prec_assertion_per = np.abs(
        true_prec_dataframe_per.sub(litterature_true_prec_per))
    p_t_te_me_assertion_per = np.abs(
        p_t_te_me_dataframe_per.sub(litterature_p_t_te_me_per))
    tol_interval_assertion_per = np.abs(
        tol_interval_dataframe_per.sub(litterature_tol_interval_per))

    # We concatenate into only one matrice for each table

    true_prec_assertion = pd.concat(
        [true_prec_assertion_abs, true_prec_assertion_per], axis=1)
    p_t_te_me_assertion = pd.concat(
        [p_t_te_me_assertion_abs, p_t_te_me_assertion_per], axis=1)
    tol_interval_assertion = pd.concat(
        [tol_interval_assertion_abs, tol_interval_assertion_per], axis=1)

    #Linear model that pass through 0 are failing at the moment and need to be dropped from the test

    reg_params_assertion.drop(reg_params_assertion.index[0:3], inplace=True)
    x_calc_assertion.drop(columns=["Linear through 0"], inplace=True)
    true_prec_assertion.drop(true_prec_assertion.index[0:4], inplace=True)
    rel_acc_assertion.drop(columns=["Linear through 0"], inplace=True)
    p_t_te_me_assertion.drop(p_t_te_me_assertion.index[0:4], inplace=True)
    tol_interval_assertion.drop(tol_interval_assertion.index[0:4],
                                inplace=True)

    # We accept a maximum of 0.05% deviation from the literature value
    # However, due to rounding in the absolute bias of the linear model in the literature we need to allow one value to
    # be over 0.05% variation (Literature value: 2.202e-3, Valexa value: 2.02016e-3)

    assert len(
        reg_params_assertion[reg_params_assertion.ge(0.05).any(axis=1)]) == 0
    assert len(x_calc_assertion[x_calc_assertion.ge(0.05).any(axis=1)]) == 0
    assert len(
        true_prec_assertion[true_prec_assertion.ge(0.05).any(axis=1)]) == 1
    assert len(rel_acc_assertion[rel_acc_assertion.ge(0.05).any(axis=1)]) == 0
    assert len(tol_interval_assertion[tol_interval_assertion.ge(0.05).any(
        axis=1)]) == 0

    return True
Exemplo n.º 5
0
 def test_data(self):
     data = dataset("feinberg_nicotinamide")
     return DataObject(data["Validation"], data["Calibration"])
Exemplo n.º 6
0
def test_feinberg_coli():
    """
    Dataset from Feinberg, M. et al., Validation of Alternative Methods for the Analysis of Drinking Water and Their
    Application to Escherichia coli (2011), https://dx.doi.org/10.1128/AEM.00020-11

    This is an example of validation with absolute unit, in this case a bacterial count.
    Here the raw data are manipulated before being passed to the algorithm. They are transformed in their log10
    equivalent and the target level are using the median instead of the mean. Please refer to the article for more
    information.

    The reference DataFrame is as follow:

         | repeatability_std | inter_series_std | tolerance_std | bias  | abs_tolerance_low | abs_tolerance_high
    -----+-------------------+------------------+---------------+-------+-------------------+--------------------
      1  | 0.141             | 0.092            | 0.173         | 0.024 | -0.206            | 0.254
    -----+-------------------+------------------+---------------+-------+-------------------+--------------------
      2  | 0.093             | 0.081            | 0.127         | 0.055 | -0.115            | 0.225
    -----+-------------------+------------------+---------------+-------+-------------------+--------------------
      3  | 0.099             | 0.141            | 0.178         | 0.093 | -0.147            | 0.333

    Note: the kM value given in the article is equivalent to kIT * sqrt(1 + (1/(nb_measures * b_coefficient)), the
    tolerance interval obtained stays the same since Valexa add this factor in the calculation of the tolerance standard
    deviation instead of the calculation of the coverage factor as found in the article. In the same way, the sFI needs
    to be divided by the same equation.
    The reference DataFrame is as follow:

    """
    data = sample_dataset.dataset("feinberg_coli")

    data["Validation"]["x"] = np.log10(data["Validation"]["x"])
    data["Validation"]["y"] = np.log10(data["Validation"]["y"])
    for level in data["Validation"]["Level"].unique():
        data["Validation"].loc[data["Validation"]["Level"] == level,"x"] = \
            np.median(data["Validation"][data["Validation"]["Level"] == level]["x"])

    profiles: ProfileManager = ProfileManager("Test",
                                              data,
                                              absolute_acceptance=True,
                                              acceptance_limit=0.3)
    profiles.make_profiles()

    litterature_dataframe: pd.DataFrame = pd.DataFrame({
        "repeatability_std": {
            1: 0.141,
            2: 0.093,
            3: 0.099
        },
        "inter_series_std": {
            1: 0.092,
            2: 0.081,
            3: 0.141
        },
        "tolerance_std": {
            1: 0.173,
            2: 0.127,
            3: 0.178
        },
        "bias": {
            1: 0.024,
            2: 0.055,
            3: 0.093
        },
        "abs_tolerance_low": {
            1: -0.206,
            2: -0.115,
            3: -0.147
        },
        "abs_tolerance_high": {
            1: 0.254,
            2: 0.225,
            3: 0.333
        },
    })

    results_dataframe: pd.DataFrame = profiles.profiles["Direct"][
        0].get_profile_parameter(
            ["repeatability_std", "inter_series_std", "tolerance_std",
             "bias"]).round(3)

    results_dataframe[[
        "abs_tolerance_low", "abs_tolerance_high"
    ]] = pd.DataFrame(profiles.profiles["Direct"][0].get_profile_parameter(
        ["abs_tolerance"])).transpose().round(3)

    assertion_dataframe = np.abs(
        litterature_dataframe.sub(results_dataframe).divide(
            litterature_dataframe) * 100)

    # We allow 0.5% since most number have only 3 significants figures. One the data has a 0.001 absolute deviation
    # which translate to a > 0.5% error (Literature: 0.178, Valexa: 0.177), probably due to rounding. We take it into
    # account during the assert.

    assert len(
        assertion_dataframe[assertion_dataframe.ge(0.5).any(axis=1)]) == 1
    return True
Exemplo n.º 7
0
def test_feinberg_labostat():
    """
    Dataset from:
    Feinberg, M., Labo-Stat (2010), https://www.lavoisier.fr/livre/sciences-de-la-vie/labo-stat/feinberg/descriptif-9782743014261

    The reference DataFrame for the model is as follow:

     Serie | x      | Intercept
    -------+--------+--------
     1     | 70.986 | -5.494
    -------+--------+--------
     2     | 69.875 | -5.100
    -------+--------+--------
     3     | 69.167 | -5.767

    Note: There seems to be a slight disrepancy in some value, especially for very small one variance, rounding errors
    have a large effect at very low level of variance. For this reason we only assert the recovery, relative tolerance
    interval, the models and the limit of quantification.
    """
    data = sample_dataset.dataset("feinberg_nicotinamide")

    profiles: ProfileManager = ProfileManager("Test",
                                              data,
                                              acceptance_limit=10,
                                              tolerance_limit=80,
                                              model_to_test="Linear")
    profiles.make_profiles()

    literature_model_dataframe: pd.DataFrame = pd.DataFrame({
        "x": {
            1: 70.986,
            2: 69.875,
            3: 69.167
        },
        "Intercept": {
            1: -5.494,
            2: -5.100,
            3: -5.767
        }
    })
    literature_dataframe: pd.DataFrame = pd.DataFrame({
        "recovery": {
            1: 102.3,
            2: 100.5,
            3: 98.9
        },
        "rel_tolerance_low": {
            1: 93.9,
            2: 95.7,
            3: 95.6
        },
        "rel_tolerance_high": {
            1: 110.7,
            2: 105.4,
            3: 102.1
        }
    })

    calculated_model_dict = {}
    for key, value in profiles.profiles["Linear"][0].model.fit.items():
        calculated_model_dict[key] = value.params

    calculated_model_dataframe = pd.DataFrame(
        calculated_model_dict).transpose().round(3)

    calculated_dataframe: pd.DataFrame = pd.DataFrame(
        profiles.profiles["Linear"][0].get_profile_parameter(["recovery"]),
        index=["recovery"]).transpose().round(1)

    calculated_dataframe[[
        "rel_tolerance_low", "rel_tolerance_high"
    ]] = pd.DataFrame(profiles.profiles["Linear"][0].get_profile_parameter(
        ["rel_tolerance"])).transpose().round(1)

    assertion_dataframe = np.abs(
        calculated_dataframe.sub(literature_dataframe))
    assertion_model_dataframe = np.abs(
        calculated_model_dataframe.sub(literature_model_dataframe).div(
            literature_model_dataframe) * 100)

    assert np.abs(
        (0.4473 - profiles.profiles["Linear"][0].min_loq) / 0.4473 * 100) < 5
    assert len(assertion_dataframe[assertion_dataframe.ge(1).any(axis=1)]) == 0
    assert len(
        assertion_model_dataframe[assertion_model_dataframe.ge(0.01).any(
            axis=1)]) == 0

    return True