6.16 Weighted Covering

Weighted Covering

R figure

Python figure

Code
import numpy as np
import matplotlib.pyplot as plt
from math import log2

c = 1
pos = c * 50
neg = 50
Pos = pos
Neg = neg

def entropy(P, N):
    if P == 0 or N == 0:
        return 0
    p = P / (P + N)
    n = N / (P + N)
    return -p * log2(p) - n * log2(n)

def gini(P, N):
    p = P / (P + N)
    n = N / (P + N)
    return 4 * p * n

def metric(tp, fp, m):
    if tp + fp == 0:
        return 0
    N = Pos + Neg
    FN = Pos - tp
    TN = Neg - fp
    if m == 'accuracy':
        return (tp + TN) / N
    if m == 'wracc':
        return tp / N - (tp + fp) * (tp + FN) / (N ** 2)
    if m == 'precision':
        return tp / (tp + fp)
    if m == 'f-measure':
        return 2 * tp / (2 * tp + fp + FN)

def rocgrid():
    fig, ax = plt.subplots(figsize=(6, 6))
    ax.set_xlim(0, neg)
    ax.set_ylim(0, pos)
    ax.set_xticks(np.arange(0, neg + 1, 10))
    ax.set_yticks(np.arange(0, pos + 1, 10))
    ax.grid(True, color='gray', linestyle='--', linewidth=0.5)
    ax.set_xlabel('Negatives')
    ax.set_ylabel('Positives')
    return ax

def contour1(ax, m, color, linestyle, tp, fp):
    v = metric(tp, fp, m)
    if m == 'wracc':
        r = max(0, min(1 - 4 * v, 1))
        g = max(0, 2 * v + 0.5)
        b = 0
    else:
        r = min(2 - 2 * v, 1)
        g = v
        b = 0
    plot_color = (r, g, b)
    if linestyle == 0:
        ls = 'solid'
    else:
        ls = linestyle
    lwd = 4 if ls == 'solid' else 3
    if linestyle == 0:
        lwd = 1
    ax.plot(fp, tp, marker='o', color=plot_color, markersize=lwd)
    if tp == 0 or fp == 0:
        return
    x = np.arange(0, fp + 1)
    y = np.arange(0, tp + 1)
    Z = np.zeros((len(y), len(x)))
    for i, xi in enumerate(x):
        for j, yj in enumerate(y):
            Z[j, i] = metric(yj, xi, m)
    cs = ax.contour(x, y, Z, levels=[v], colors=[plot_color], linestyles=ls, linewidths=lwd - 1)


def contour2(ax, m, color, linestyle, tp, fp, tpc, fpc):
    global Pos, Neg
    Pos1, Neg1 = Pos, Neg
    Pos, Neg = 50, 50
    contour1(ax, m, color, 0, tp, fp)
    w = 0.5
    fp1 = fp - (1 - w) * fpc
    tp1 = tp - (1 - w) * tpc
    dx = 0.4 if fp == 0 else 0
    dy = 0.4 if tp == 0 else 0
    ax.arrow(fp + dx, tp + dy, fp1 - fp, tp1 - tp, color='violet', width=0.2, head_width=1.5, length_includes_head=True)
    Pos, Neg = Pos1, Neg1
    contour1(ax, m, color, linestyle, tp1, fp1)

ax = rocgrid()
method = 'wracc'
Pos, Neg = 45, 35
colour = 'blue'
ax.add_patch(plt.Rectangle((0, 0), Neg, Pos, fill=False, edgecolor=colour, linewidth=2))

contour2(ax, method, colour, 'dotted', 50, 50, 10, 30)
contour2(ax, method, colour, 'dotted', 50, 30, 10, 20)
contour2(ax, method, colour, 'dotted', 50, 10, 10, 10)

plt.title("WRAcc Contours with Arrows")
plt.show()