spotify_confidence/analysis/abstract_base_classes/confidence_abc.py (115 lines of code) (raw):
# Copyright 2017-2020 Spotify AB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from abc import ABC, abstractmethod
from typing import Union, Iterable, Tuple, List
from pandas import DataFrame
from spotify_confidence.chartgrid import ChartGrid
from .confidence_computer_abc import ConfidenceComputerABC
from .confidence_grapher_abc import ConfidenceGrapherABC
from ..constants import NIM_TYPE
class ConfidenceABC(ABC):
@property
def _confidence_computer(self) -> ConfidenceComputerABC:
return self._computer
@_confidence_computer.setter
def _confidence_computer(self, computer: ConfidenceComputerABC):
self._computer = computer
@property
def _confidence_grapher(self) -> ConfidenceGrapherABC:
return self._grapher
@_confidence_grapher.setter
def _confidence_grapher(self, grapher: ConfidenceGrapherABC):
self._grapher = grapher
@abstractmethod
def __init__(
self,
data_frame: DataFrame,
numerator_column: str,
numerator_sum_squares_column: Union[str, None],
denominator_column: str,
categorical_group_columns: Union[str, Iterable, None],
ordinal_group_column: Union[str, None],
interval_size: float,
correction_method: str,
metric_column: Union[str, None],
treatment_column: Union[str, None],
power: float,
):
pass
@abstractmethod
def summary(self, verbose: bool) -> DataFrame:
"""Args:
verbose (bool): include columns used in intermediate steps in the calculations in returned dataframe.
Returns:
Dataframe containing summary statistics
"""
pass
@abstractmethod
def difference(
self,
level_1: Union[str, Tuple],
level_2: Union[str, Tuple],
absolute: bool,
groupby: Union[str, Iterable],
non_inferiority_margins: NIM_TYPE,
final_expected_sample_size_column: str,
verbose: bool,
minimum_detectable_effects_column: str,
) -> DataFrame:
"""Args:
groupby (str): Name of column.
If specified, will plot a separate chart for each level of the
grouping.
non_inferiority_margins (Union[Tuple[float, str], Dict[str, Tuple[float, str]], bool]):
Pass tuple(non_inferiority_margin, preferred direction) to use the same NIM for all
comparisons, e.g. (0.01, 'increase'), which means that we want
level_2 to be grater than the average of level_1 times (1-0.01),
or (0.05, 'decrease') which means that we want
level_2 to be smaller than the average
of level_1 times (1+0.01).
Pass dictionary {{group:tuple(non_inferiority_margin, preferred direction}} to use
different non-inferiority margins for different values of
groupby column.
To performe a one-sided test without nim, use
(None, preffered direction).
Alternatively, pass True to use the "non_inferiority_margin" and "preferred_direction"
columns of dataframe that was passed to the contructor, as source of nims.
final_expected_sample_size_column (str): Column in source data frame containing expected number of
observations at end of experiment.
Use in combination with ordinal groupby to perform a
sequential test. See https://cran.r-project.org/web/packages/ldbounds/index.html for details.
verbose (bool): include columns used in intermediate steps in the calculations in returned dataframe.
minimum_detectable_effects_column (str): The minimum detectable effect, used for calculating required
sample size.
Returns:
Dataframe containing the difference in means between
group 1 and 2, p-values and confidence intervals for each value
in the groupby column
"""
pass
@abstractmethod
def differences(
self,
levels: List[Tuple],
absolute: bool,
groupby: Union[str, Iterable],
non_inferiority_margins: NIM_TYPE,
final_expected_sample_size_column: str,
verbose: bool,
minimum_detectable_effects_column: str,
) -> DataFrame:
"""Args:
levels: (list(tuple)): list of levels to compare
groupby (str): Name of column.
If specified, will plot a separate chart for each level of the
grouping.
non_inferiority_margins (Union[Tuple[float, str], Dict[str, Tuple[float, str]], bool]):
Pass tuple(non_inferiority_margin, preferred direction) to use the same NIM for all
comparisons, e.g. (0.01, 'increase'), which means that we want
level_2 to be grater than the average of level_1 times (1-0.01),
or (0.05, 'decrease') which means that we want
level_2 to be smaller than the average
of level_1 times (1+0.01).
Pass dictionary {{group:tuple(non_inferiority_margin, preferred direction}} to use
different non-inferiority margins for different values of
groupby column.
To performe a one-sided test without nim, use
(None, preffered direction).
Alternatively, pass True to use the "non_inferiority_margin" and "preferred_direction"
columns of dataframe that was passed to the contructor, as source of nims.
final_expected_sample_size_column (str): Column in source data frame containing expected number of
observations at end of experiment.
Use in combination with ordinal groupby to perform a
sequential test. See https://cran.r-project.org/web/packages/ldbounds/index.html for details.
verbose (bool): include columns used in intermediate steps in the calculations in returned dataframe.
minimum_detectable_effects_column (str): The minimum detectable effect, used for calculating required
sample size.
Returns:
Dataframe containing the difference in means between
group 1 and 2, p-values and confidence intervals for each value
in the groupby column
"""
pass
@abstractmethod
def multiple_difference(
self,
level: Union[str, Tuple],
absolute: bool,
groupby: Union[str, Iterable],
level_as_reference: bool,
non_inferiority_margins: NIM_TYPE,
final_expected_sample_size_column: str,
verbose: bool,
minimum_detectable_effects_column: str,
) -> DataFrame:
"""Args:
groupby (str): Name of column.
If specified, will plot a separate chart for each level of the
grouping.
level_as_reference (bool):
If false, compare level to all other
groups. If true, compare all other groups to level.
non_inferiority_margins (Union[Tuple[float, str],
Dict[str, Tuple[float, str]]]):
Pass tuple(nim, preferred direction) to use the same NIM for all
comparisons, e.g. (0.01, 'increase'), which means that we want
level_2 to be grater than the average of level_1 times (1-0.01),
or (0.05, 'decrease') which means that we want
level_2 to be smaller than the average
of level_1 times (1+0.01).
Pass dictionary {{group:tuple(nim, preferred direction}} to use
different non-inferiority margins for different values of
groupby column.
To performe a one-sided test without nim, use
(None, preffered direction).
Alternatively, pass True to use the "non_inferiority_margin" and "preferred_direction"
columns of dataframe that was passed to the contructor, as source of nims.
final_expected_sample_size_column (str): Column in source data frame containing expected number of
observations at end of experiment.
Use in combination with ordinal groupby to perform a
sequential test. See https://cran.r-project.org/web/packages/ldbounds/index.html for details.
verbose (bool): include columns used in intermediate steps in the calculations in returned dataframe.
minimum_detectable_effects_column (str): The minimum detectable effect, used for calculating required
sample size.
Returns:
Dataframe containing the difference in means between
group 1 and 2, p-values and confidence intervals for each value
in the groupby column
"""
pass
@abstractmethod
def summary_plot(self, groupby: Union[str, Iterable]) -> ChartGrid:
"""Plot for each group in the data_frame:
if ordinal level exists:
line graph with area to represent confidence interval
if categorical levels:
Interval plots of confidence intervals by group
Args:
groupby (str): Name of column.
If specified, will plot a separate chart for each level of the
grouping.
Returns:
ChartGrid object and a DataFrame with numerical results.
"""
pass
@abstractmethod
def difference_plot(
self,
level_1: Union[str, Tuple],
level_2: Union[str, Tuple],
absolute: bool,
groupby: Union[str, Iterable],
non_inferiority_margins: NIM_TYPE,
use_adjusted_intervals: bool,
final_expected_sample_size_column: str,
split_plot_by_groups: bool,
) -> ChartGrid:
"""Plot representing the difference between group 1 and 2.
- Difference in means or proportions, depending
on the response variable type.
- Plot interval plot with confidence interval of the
difference between groups
Args:
level_1 (str, tuple of str): Name of first level.
level_2 (str, tuple of str): Name of second level.
absolute (bool): If True then return the absolute
difference (level2 - level1)
otherwise return the relative difference (level2 / level1 - 1)
groupby (str): Name of column, or list of columns.
If specified, will return an interval for each level
of the grouped dimension, or a confidence band if the
grouped dimension is ordinal
non_inferiority_margins (Union[Tuple[float, str],
Dict[str, Tuple[float, str]]]):
Pass tuple(nim, preferred direction) to use the same NIM for all
comparisons, e.g. (0.01, 'increase'), which means that we want
level_2 to be grater than the average of level_1 times (1-0.01),
or (0.05, 'decrease') which means that we want
level_2 to be smaller than the average
of level_1 times (1+0.01).
Pass dictionary {{group:tuple(nim, preferred direction}} to use
different non-inferiority margins for different values of
groupby column.
To performe a one-sided test without nim, use
(None, preffered direction).
use_adjusted_intervals (bool):
If true, use e.g. bon-ferroni corrected
(or other method provided) confidence intervals
final_expected_sample_size_column (str): Column in source data frame containing expected number of
observations at end of experiment.
Use in combination with ordinal groupby to perform a
sequential test. See https://cran.r-project.org/web/packages/ldbounds/index.html for details.
split_plot_by_groups (bool): create a separate chart for each group in the groupby argument.
Returns:
Chartify Chart object and a DataFrame with numerical results.
"""
@abstractmethod
def differences_plot(
self,
levels: List[Tuple],
absolute: bool,
groupby: Union[str, Iterable],
non_inferiority_margins: NIM_TYPE,
use_adjusted_intervals: bool,
final_expected_sample_size_column: str,
split_plot_by_groups: bool,
) -> ChartGrid:
"""Plot representing the difference between group 1 and 2.
- Difference in means or proportions, depending
on the response variable type.
- Plot interval plot with confidence interval of the
difference between groups
Args:
levels: (list(tuple)): list of levels to compare
absolute (bool): If True then return the absolute
difference (level2 - level1)
otherwise return the relative difference (level2 / level1 - 1)
groupby (str): Name of column, or list of columns.
If specified, will return an interval for each level
of the grouped dimension, or a confidence band if the
grouped dimension is ordinal
non_inferiority_margins (Union[Tuple[float, str],
Dict[str, Tuple[float, str]]]):
Pass tuple(nim, preferred direction) to use the same NIM for all
comparisons, e.g. (0.01, 'increase'), which means that we want
level_2 to be grater than the average of level_1 times (1-0.01),
or (0.05, 'decrease') which means that we want
level_2 to be smaller than the average
of level_1 times (1+0.01).
Pass dictionary {{group:tuple(nim, preferred direction}} to use
different non-inferiority margins for different values of
groupby column.
To performe a one-sided test without nim, use
(None, preffered direction).
use_adjusted_intervals (bool):
If true, use e.g. bon-ferroni corrected
(or other method provided) confidence intervals
final_expected_sample_size_column (str): Column in source data frame containing expected number of
observations at end of experiment.
Use in combination with ordinal groupby to perform a
sequential test. See https://cran.r-project.org/web/packages/ldbounds/index.html for details.
split_plot_by_groups (bool): create a separate chart for each group in the groupby argument.
Returns:
Chartify Chart object and a DataFrame with numerical results.
"""
@abstractmethod
def multiple_difference_plot(
self,
level: Union[str, Tuple],
absolute: bool,
groupby: Union[str, Iterable],
level_as_reference: bool,
non_inferiority_margins: NIM_TYPE,
use_adjusted_intervals: bool,
final_expected_sample_size_column: str,
split_plot_by_groups: bool,
) -> ChartGrid:
"""Compare level to all other groups or, if level_as_reference = True,
all other groups to level.
Args:
level (str, tuple of str): Name of level.
absolute (bool): If True then return the absolute
difference (level2 - level1)
otherwise return the relative difference (level2 / level1 - 1)
groupby (str): Name of column, or list of columns.
If specified, will return an interval for each level
of the grouped dimension, or a confidence band if the
grouped dimension is ordinal
level_as_reference: If false, compare level to all other
groups. If true, compare all other groups to level.
non_inferiority_margins (Union[Tuple[float, str],
Dict[str, Tuple[float, str]]]):
Pass tuple(nim, preferred direction) to use the same NIM for all
comparisons, e.g. (0.01, 'increase'), which means that we want
level_2 to be grater than the average of level_1 times (1-0.01),
or (0.05, 'decrease') which means that we want
level_2 to be smaller than the average
of level_1 times (1+0.01).
Pass dictionary {{group:tuple(nim, preferred direction}} to use
different non-inferiority margins for different values of
groupby column.
To performe a one-sided test without nim, use
(None, preffered direction).
use_adjusted_intervals (bool):
If true, use e.g. bon-ferroni corrected
(or other method provided) confidence intervals
final_expected_sample_size_column (str): Column in source data frame containing expected number of
observations at end of experiment.
Use in combination with ordinal groupby to perform a
sequential test. See https://cran.r-project.org/web/packages/ldbounds/index.html for details.
split_plot_by_groups (bool): create a separate chart for each group in the groupby argument.
Returns:
ChartGrid object and a DataFrame with numerical results.
"""