CoolFace
Apppublic

glaria/app-project-huggingface

sourceHugging Faceccupdated 3y agoView on Hugging Face
0likes
app_functions.py311 linesDownload Raw Back to root
1import pandas as pd2import numpy as np3import math4import base645import scipy.special as scsp6from sklearn.tree import _tree7from matplotlib import pyplot as plt8 9 10significance_treshold = 0.0511 12 13def z2p(z):14    """From z-score return p-value."""15    return 2*(1- (0.5 * (1 + scsp.erf(abs(z) / math.sqrt(2)))))16 17def zscore(p1, p2, n1, n2): # p1, p2 proportions18    """ Obtain zscore of 2 proportions sample """19    p = (p1*float(n1) + p2*float(n2))/(float(n1) + float(n2))20    numerator = p1 - p221    denominator = math.sqrt(p*(1-p)*((1/n1)+(1/n2)))22    return numerator/denominator23 24def kadane_algorithm(input_list):25    max_current = max_global = input_list[0]26    start = end = 027    for i in range(1, len(input_list)):28        if input_list[i] > max_current + input_list[i]:29            max_current = input_list[i]30            start = i31        else:32            max_current += input_list[i]33        if max_current > max_global:34            max_global = max_current35            end = i36    return max_global, start, end37 38def kadane_algorithm_mod(input_list):39    curr_sum = max_total = input_list[0]40    start = end = 041    for i in range(1, len(input_list)):42        curr_sum += input_list[i]43        if curr_sum > max_total:44            max_total = curr_sum45            end = i46        if curr_sum < 0:47            curr_sum = 048    curr_sum = 049    for i in range(end, -1, -1): #second iteration for identifying the start of the interval of max sum50        curr_sum += input_list[i]51        if curr_sum == max_total:52            start = i53            break54    return max_total, start, end55 56def get_negative_array(values):57    transformed_list = []58    for value in values:59        if value > 0.5:60            transformed_list.append(-1)61        elif value < -0.5:62            transformed_list.append(1)63        else:64            transformed_list.append(value)65    return transformed_list66 67 68####***Functions used during dataload***####69def infer_datatypes_and_metatypes(dataset: pd.DataFrame) -> pd.DataFrame:70    info_data = {'COLUMN': [], 'DATATYPE': [], 'METATYPE': []}71 72    for column in dataset.columns:73        dtype = dataset[column].dtype74 75        if column == 'CUSTOMERNUMBER':76            info_data['COLUMN'].append(column)77            info_data['DATATYPE'].append('NUMERIC')78            info_data['METATYPE'].append('PK')79        elif column == 'TGCG':80            info_data['COLUMN'].append(column)81            info_data['DATATYPE'].append('STRING')82            info_data['METATYPE'].append('TGCG')83        else:84            info_data['COLUMN'].append(column)85 86            if dtype == 'bool':87                info_data['DATATYPE'].append('BOOL')88                info_data['METATYPE'].append('KPI')89            elif dtype == 'object':90                info_data['DATATYPE'].append('STRING')91                info_data['METATYPE'].append('SF')92            elif dataset[column].nunique() < 10:93                info_data['DATATYPE'].append('NUM_ST')94                info_data['METATYPE'].append('SF')95            else:96                info_data['DATATYPE'].append('NUMERIC')97                info_data['METATYPE'].append('SF')98 99    inferred_info_dataset = pd.DataFrame(info_data)100    return inferred_info_dataset101 102def validate_datatypes_and_metatypes(dataset: pd.DataFrame, info_dataset: pd.DataFrame) -> bool:103    datatype_values = ['BOOL', 'STRING', 'NUM_ST', 'NUMERIC']104    metatype_values = ['TGCG', 'PK', 'KPI', 'SF']105 106    for index, row in info_dataset.iterrows():107        column = row['COLUMN']108        datatype = row['DATATYPE']109        metatype = row['METATYPE']110 111        if datatype not in datatype_values or metatype not in metatype_values:112            return False113 114        if metatype == 'TGCG' and not dataset[column].apply(lambda x: x.lower() in ['target', 'control'] if pd.notnull(x) else True).all():115            return False116 117        if datatype == 'BOOL' and not dataset[column].apply(lambda x: isinstance(x, bool) if pd.notnull(x) else True).all():118            return False119 120        if datatype == 'STRING' and not dataset[column].apply(lambda x: isinstance(x, str) if pd.notnull(x) else True).all():121            return False122 123        if datatype == 'NUM_ST' and not (dataset[column].nunique() < 10 and dataset[column].apply(lambda x: isinstance(x, (int, float)) if pd.notnull(x) else True).all()):124            return False125 126        if datatype == 'NUMERIC' and not dataset[column].apply(lambda x: isinstance(x, (int, float)) if pd.notnull(x) else True).all():127            return False128 129        if metatype == 'KPI' and not dataset[column].apply(lambda x: isinstance(x, (int, float)) if pd.notnull(x) else True).all():130            return False131 132    return True133###***    ***###134 135def format_float(value):136    if isinstance(value, float):137        return "{:.2f}".format(value)138    return value139 140 141def calculate_metrics2(subset, kpi, tgcg_column):142    """Calculates metrics for a specific KPI."""143    metrics = []144    tg_acceptors = subset.loc[subset[tgcg_column] == 'target', kpi].sum()145    tg_total = len(subset.loc[subset[tgcg_column] == 'target'])146    tg_acceptance = round((tg_acceptors / tg_total)*100,2) if tg_total != 0 else 0147 148    cg_acceptors = subset.loc[subset[tgcg_column] == 'control', kpi].sum()149    cg_total = len(subset.loc[subset[tgcg_column] == 'control'])150    cg_acceptance = round((cg_acceptors / cg_total) * 100, 2) if cg_total != 0 else 0151 152    uplift = tg_acceptance - cg_acceptance153    p_value = z2p(zscore(float(tg_acceptors)/float(tg_total), float(cg_acceptors)/float(cg_total),float(tg_total), float(cg_total))) if tg_total != 0 and cg_total != 0 else None154    155    metrics.append([kpi, "{:.2f}".format(tg_acceptors), "{:.2f}".format(tg_acceptance), "{:.2f}".format(cg_acceptors), "{:.2f}".format(cg_acceptance), "{:.2f}".format(uplift), p_value])156    result_df = pd.DataFrame(metrics, columns=["KPI", "TG Acceptors", "TG Acceptance (%)", "CG Acceptors", "CG Acceptance (%)", "Uplift (%)", "P-value"])157    result_df['P-value'] = pd.to_numeric(result_df['P-value'], errors='coerce')158    return result_df159 160 161def highlight_pvalue(row):162    """Highlights rows with P-value <= significance_treshold."""163    if float(row["P-value"]) <= significance_treshold and float(row["Uplift (%)"]) >= 0:164        return ["background-color: #CCFFCC"] * len(row)165    elif float(row["P-value"]) <= significance_treshold and float(row["Uplift (%)"]) < 0:166        return ["background-color: #FFEAEA"] * len(row)167    else:168        return [""] * len(row)169 170def calculate_metrics(df, kpi_columns, tgcg_column):171    """Calculates metrics for a list of KPIs."""172    metrics = []173    for kpi in kpi_columns:174        tg = df[df[tgcg_column] == 'target']175        cg = df[df[tgcg_column] == 'control']176 177        tg_acceptors = tg[kpi].sum()178        tg_total = len(tg)179        tg_acceptance = round((tg_acceptors / tg_total)*100,2) if tg_total != 0 else 0180 181        cg_acceptors = cg[kpi].sum()182        cg_total = len(cg)183        cg_acceptance = round((cg_acceptors / cg_total) * 100, 2) if cg_total != 0 else 0184 185        uplift = tg_acceptance - cg_acceptance186        p_value = z2p(zscore(tg_acceptors/tg_total, cg_acceptors/cg_total, tg_total, cg_total)) if tg_total != 0 and cg_total != 0 else None187 188        metrics.append([kpi, "{:.2f}".format(tg_acceptors), "{:.2f}".format(tg_acceptance), "{:.2f}".format(cg_acceptors), "{:.2f}".format(cg_acceptance), "{:.2f}".format(uplift), p_value])189 190    result_df = pd.DataFrame(metrics, columns=["KPI", "TG Acceptors", "TG Acceptance (%)", "CG Acceptors", "CG Acceptance (%)", "Uplift (%)", "P-value"])191    result_df['P-value'] = pd.to_numeric(result_df['P-value'], errors='coerce')192 193    return result_df194 195def filter_and_display(df, pvalue_threshold, seg_column, unique_value):196    """Filters and displays the results."""197    df = df[df['P-value'] <= pvalue_threshold]198    if not df.empty:199        print(f"Segment: {seg_column} = {unique_value}")200        print(df.to_string(index=False)) # Display the dataframe without the index201 202def download_csv_link(df, filename, message="Click here to download this table"):203    csv = df.to_csv(index=False)204    b64 = base64.b64encode(csv.encode()).decode()205    href = f'<a href="data:file/csv;base64,{b64}" download="{filename}">{message}</a>'206    return href207 208###*** Functions exclusive of the Advanced Analytics page ***###209def oversample(df, group_cols):210    # biggest group in terms of size211    max_size = df[group_cols].value_counts().max()212    # empty df that will be filled in213    df_oversampled = pd.DataFrame()214    # group columns per group_cols and oversample each of the groups215    for group, group_df in df.groupby(group_cols):216        oversampled_group = group_df.sample(max_size, replace=True)217        df_oversampled = pd.concat([df_oversampled, oversampled_group], axis=0)218 219    # return oversampled dataframe220    return df_oversampled221 222def get_rules(tree, feature_names, class_names, class_of_interest):223    """ Extract the rules of a decisition tree algorithm """224    tree_ = tree.tree_225    feature_name = [226        feature_names[i] if i != _tree.TREE_UNDEFINED else "undefined!"227        for i in tree_.feature228    ]229 230    paths = []231    path = []232 233    def recurse(node, path, paths):234 235        if tree_.feature[node] != _tree.TREE_UNDEFINED:236            name = feature_name[node]237            threshold = tree_.threshold[node]238            p1, p2 = list(path), list(path)239            240            # Check if the feature is a result of one-hot encoding241            if '==' in name:242                feature, value = name.split('==')243                p1 += [f"({feature} <> {value})"]244                p2 += [f"({feature} = {value})"]245            else:246                p1 += [f"({name} <= {np.round(threshold, 2)})"]247                p2 += [f"({name} > {np.round(threshold, 2)})"]248            249            recurse(tree_.children_left[node], p1, paths)250            recurse(tree_.children_right[node], p2, paths)251        else:252            path += [(tree_.value[node], tree_.n_node_samples[node])]253            paths += [path]254 255    recurse(0, path, paths)256 257    # sort by samples count258    paths = sorted(paths, key=lambda x: x[-1][1], reverse=True)259    # generate rules260    rules = []261    for path in paths:262        rule = ""263 264        for p in path[:-1]:265            if rule != "":266                rule += " and \n"267            rule += str(p)268        269        if class_names[np.argmax(path[-1][0][0])] == class_of_interest:270            rule += f"\n\n**(samples: {path[-1][1]})**"271            rules.append(rule)272 273    return rules274 275def qini_curve(y_true, uplift_score):276    # Sorting data by the uplift score277    data = pd.DataFrame({'y_true': y_true, 'uplift_score': uplift_score}).sort_values('uplift_score', ascending=False)278    data.reset_index(drop=True, inplace=True)279    280    data['target_cumsum'] = data.y_true.cumsum()281    data['all_cumnum'] = range(1, len(data) + 1)282 283    # Calculating the cumulative uplift as proportion284    data['uplift_cum'] = data['target_cumsum'] / data['all_cumnum'] - data.iloc[0]['target_cumsum'] / len(data)285    data['proportion_targeted'] = data['all_cumnum'] / len(data)  # new line to calculate proportion targeted286 287    # Calculating the baseline (random model)288    random_model = data['target_cumsum'].iloc[-1] / len(data) * data['proportion_targeted']289 290    # Creating a figure and an axis291    fig, ax = plt.subplots()292 293    # Drawing the Qini curve with proportion targeted on x-axis294    ax.plot(data['proportion_targeted'], data['uplift_cum'], label='Model')295 296    # Drawing the baseline with proportion targeted297    ax.plot(data['proportion_targeted'], random_model, label='Random')298 299    # Labels and legend300    ax.set_xlabel('Proportion targeted')301    ax.set_ylabel('Cumulative Uplift')302    ax.legend()303 304    # Calculating the Qini area305    qini_area = (data['uplift_cum'] - random_model).sum() / len(data)306 307    return fig, ax, qini_area308 309 310 311