Friday, October 22, 2021

AWK: count which customer has the most unique accounts

Content of the count_uniq.awk script:


BEGIN {
    FS=",";
}
{
    if ($0 in seen == 0){arr[$2]++} else {seen[$0]=1}
    seen[$0]=1;
}
END {
    for (a in arr) print a, arr[a]
}


What it does?

count how many accounts does each customer has, ignoring duplicated rows. Details as in image below:


Customer "a" has 3 different accounts: [1, 2, 3]

Customer "b" has 1 account: [2]

Customer "c" has 2 accounts: [1, 2]


Thursday, September 30, 2021

Concatenate multiple files with same headers (and only keep one header line in the output file) - Version2

 Put this into an AWK script and call it merge.awk:


BEGIN{

    h=ARGV[1];

    ARGV[1]="";

}



{

    if(FNR==1){print}

    else if($1!~h){print}

}


and use an argument:

cat *.csv | awk -f merge.awk "<header>" > output.csv

Wednesday, September 8, 2021

git: find string in a certain branch

 So, today I cloned a repo and it has many branches. I know one of the branches has a file that is updated and contains the word "token". This is how I find out which branch it is:

git branch -a | cut -c3- | cut -d' ' -f 1 | xargs git grep "token" 

Thursday, August 12, 2021

cron.allow

If a user on Linux can't run "crontab -l" or "corntab -e", add the user name to /etc/cron.allow, and then it should work. 

Wednesday, August 11, 2021

WOE

 #http://lazynight.me/4048.html

import math

import numpy as np
from scipy import stats
from sklearn.utils.multiclass import type_of_target


class WOE(object):
    def __init__(self):
        self._WOE_MIN = -20
        self._WOE_MAX = 20

    def processing(self, X, y, event=1):
        self.check_target_binary(y)
        X1 = self.feature_discretion(X)

        res_woe = []
        res_iv = []
        for i in range(0, X1.shape[-1]):
            x = X1[:, i]
            woe_dict, iv1 = self.woe_single_x(x, y, event)
            res_woe.append(woe_dict)
            res_iv.append(iv1)
        return np.array(res_woe), np.array(res_iv)

    def woe_single_x(self, x, y, event=1):
        self.check_target_binary(y)

        event_total, non_event_total = self.count_binary(y, event=event)
        x_labels = np.unique(x)
        woe_dict = {}
        iv = 0
        for x1 in x_labels:
            y1 = y[np.where(x == x1)[0]]
            event_count, non_event_count = self.count_binary(y1, event=event)
            rate_event = 1.0 * event_count / event_total
            rate_non_event = 1.0 * non_event_count / non_event_total
            if rate_event == 0:
                woe1 = self._WOE_MIN
            elif rate_non_event == 0:
                woe1 = self._WOE_MAX
            else:
                woe1 = math.log(rate_event / rate_non_event)
            woe_dict[x1] = woe1
            iv += (rate_event - rate_non_event) * woe1
        return woe_dict, iv

    def woe_replace(self, X, woe_arr):
        if X.shape[-1] != woe_arr.shape[-1]:
            raise ValueError('WOE dict array length must be equal with features length')

        res = np.copy(X).astype(float)
        idx = 0
        for woe_dict in woe_arr:
            for k in woe_dict.keys():
                woe = woe_dict[k]
                res[:, idx][np.where(res[:, idx] == k)[0]] = woe * 1.0
            idx += 1

        return res

    def combined_iv(self, X, y, masks, event=1):
        if masks.shape[-1] != X.shape[-1]:
            raise ValueError('Masks array length must be equal with features length')

        x = X[:, np.where(masks == 1)[0]]
        tmp = []
        for i in range(x.shape[0]):
            tmp.append(self.combine(x[i, :]))

        dumy = np.array(tmp)
        # dumy_labels = np.unique(dumy)
        woe, iv = self.woe_single_x(dumy, y, event)
        return woe, iv

    def combine(self, list):
        res = ''
        for item in list:
            res += str(item)
        return res

    def count_binary(self, a, event=1):
        event_count = (a == event).sum()
        non_event_count = a.shape[-1] - event_count
        return event_count, non_event_count

    def check_target_binary(self, y):
        y_type = type_of_target(y)
        if y_type not in ['binary']:
            raise ValueError('Label type must be binary')

    def feature_discretion(self, X):
        temp = []
        for i in range(0, X.shape[-1]):
            x = X[:, i]
            x_type = type_of_target(x)
            if x_type == 'continuous':
                x1 = self.discrete(x)
                temp.append(x1)
            else:
                temp.append(x)
        return np.array(temp).T

    def discrete(self, x):
        res = np.array([0] * x.shape[-1], dtype=int)
        for i in range(5):
            point1 = stats.scoreatpercentile(x, i * 20)
            point2 = stats.scoreatpercentile(x, (i + 1) * 20)
            x1 = x[np.where((x >= point1) & (x <= point2))]
            mask = np.in1d(x, x1)
            res[mask] = (i + 1)
        return res

    @property
    def WOE_MIN(self):
        return self._WOE_MIN

    @WOE_MIN.setter
    def WOE_MIN(self, woe_min):
        self._WOE_MIN = woe_min

    @property
    def WOE_MAX(self):
        return self._WOE_MAX

    @WOE_MAX.setter
    def WOE_MAX(self, woe_max):
        self._WOE_MAX = woe_max

my-alpine and docker-compose.yml

 ``` version: '1' services:     man:       build: .       image: my-alpine:latest   ```  Dockerfile: ``` FROM alpine:latest ENV PYTH...