utils.py 7.82 KB
Newer Older
1
# encoding = "utf-8"
张彦钊's avatar
张彦钊 committed
2 3
from datetime import datetime
from datetime import timedelta
4 5
import pymysql
import numpy as np
6
import redis
张彦钊's avatar
张彦钊 committed
7 8 9 10
import pandas as pd
from sklearn import metrics
from sklearn.metrics import auc
from multiprocessing import Pool
张彦钊's avatar
张彦钊 committed
11

12

张彦钊's avatar
张彦钊 committed
13 14 15 16 17 18
def get_date():
    now = datetime.now()
    year = now.year
    month = now.month
    day = now.day
    date = datetime(year,month,day)
张彦钊's avatar
张彦钊 committed
19
    data_start_date = (date - timedelta(days=31)).strftime("%Y-%m-%d")
张彦钊's avatar
张彦钊 committed
20 21 22
    data_end_date = (date - timedelta(days=1)).strftime("%Y-%m-%d")
    validation_date = (date - timedelta(days=2)).strftime("%Y-%m-%d")
    # 验证集和测试集的日期必须相差一天,否则切割数据集时会报错
张彦钊's avatar
张彦钊 committed
23 24 25 26 27 28
    test_date = data_end_date
    print("data_start_date,data_end_date,validation_date,test_date:")
    print(data_start_date,data_end_date,validation_date,test_date)
    return data_start_date,data_end_date,validation_date,test_date


张彦钊's avatar
张彦钊 committed
29 30 31 32 33 34 35 36
def get_roc_curve(y, pred, pos_label):
    """
    计算二分类问题的roc和auc
    """
    fpr, tpr, thresholds = metrics.roc_curve(y, pred, pos_label)
    AUC = metrics.auc(fpr, tpr)
    print(AUC)

37

38
# 从Tidb数据库的表里获取数据,并转化成df格式
39
def con_sql(sql):
张彦钊's avatar
张彦钊 committed
40
    db = pymysql.connect(host='10.66.157.22', port=4000, user='root', passwd='3SYz54LS9#^9sBvC', db='jerry_test')
41 42 43 44 45
    cursor = db.cursor()
    cursor.execute(sql)
    result = cursor.fetchall()
    df = pd.DataFrame(list(result)).dropna()
    db.close()
张彦钊's avatar
张彦钊 committed
46
    return df
47

张彦钊's avatar
张彦钊 committed
48

49
# 把数据写到redis里
50
# TODO 生产环境的redis地址没有提供,下面的地址是测试环境的,需要改成生产环境地址
张彦钊's avatar
张彦钊 committed
51 52
def add_data_to_redis(key, val):
    r = redis.StrictRedis(host='10.30.50.58', port=6379, db=12)
53
    r.set(key, val)
54
    # 设置key的过期时间,36小时后过期
张彦钊's avatar
张彦钊 committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
    r.expire(key, 36 * 60 * 60)


# 多线程ffm转化类:
class multiFFMFormatPandas:
    def __init__(self):
        self.field_index_ = None
        self.feature_index_ = None
        self.y = None

    def fit(self, df, y=None):
        self.y = y
        df_ffm = df[df.columns.difference([self.y])]
        if self.field_index_ is None:
            self.field_index_ = {col: i for i, col in enumerate(df_ffm)}

        if self.feature_index_ is not None:
            last_idx = max(list(self.feature_index_.values()))

        if self.feature_index_ is None:
            self.feature_index_ = dict()
            last_idx = 0

        for col in df.columns:
            vals = df[col].unique()
            for val in vals:
                if pd.isnull(val):
                    continue
                name = '{}_{}'.format(col, val)
                if name not in self.feature_index_:
                    self.feature_index_[name] = last_idx
                    last_idx += 1
            self.feature_index_[col] = last_idx
            last_idx += 1

        return self

张彦钊's avatar
张彦钊 committed
92
    def fit_transform(self, df, y=None,n=50000,processes=4):
张彦钊's avatar
张彦钊 committed
93 94 95 96
        # n是每个线程运行最大的数据条数,processes是线程数
        self.fit(df, y)
        n = n
        processes = processes
97
        return self.transform(df,n,processes)
张彦钊's avatar
张彦钊 committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

    def transform_row_(self, row, t):
        ffm = []
        if self.y is not None:
            ffm.append(str(row.loc[row.index == self.y][0]))
        if self.y is None:
            ffm.append(str(0))

        for col, val in row.loc[row.index != self.y].to_dict().items():
            col_type = t[col]
            name = '{}_{}'.format(col, val)
            if col_type.kind == 'O':
                ffm.append('{}:{}:1'.format(self.field_index_[col], self.feature_index_[name]))
            elif col_type.kind == 'i':
                ffm.append('{}:{}:{}'.format(self.field_index_[col], self.feature_index_[col], val))
        return ' '.join(ffm)

115
    def transform(self, df,n=1500,processes=2):
张彦钊's avatar
张彦钊 committed
116 117 118 119 120
        # n是每个线程运行最大的数据条数,processes是线程数
        t = df.dtypes.to_dict()
        data_list = self.data_split_line(df,n)

        # 设置进程的数量
121
        pool = Pool(processes)
张彦钊's avatar
张彦钊 committed
122
        print("总进度: " + str(len(data_list)))
张彦钊's avatar
张彦钊 committed
123 124 125
        for i in range(len(data_list)):
            data_list[i] = pool.apply_async(self.pool_function, (data_list[i], t,))

张彦钊's avatar
张彦钊 committed
126 127 128
        result_map = {}
        for i in data_list:
            result_map.update(i.get())
张彦钊's avatar
张彦钊 committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
        pool.close()
        pool.join()

        return pd.Series(result_map)

    # 多进程计算方法
    def pool_function(self, df, t):
        return {idx: self.transform_row_(row, t) for idx, row in df.iterrows()}

    # 切分数据方法,传人dataframe和切分条数的步长,返回dataframe的集合,每个dataframe中含有若干条数据
    def data_split_line(self, data, step):
        data_list = []
        x = 0
        while True:
            if x + step < data.__len__():
                data_list.append(data.iloc[x:x + step])
                x = x + step + 1
            else:
                data_list.append(data.iloc[x:data.__len__()])
                break

        '''
        # 返回生成器方法,但是本地测试效率不高
        x = 0
        while True:
            if x + step < data.__len__():
                yield data.iloc[x:x + step]
                x = x + step + 1
            else:
                yield data.iloc[x:data.__len__()]
                break
        '''

        return data_list


    # 下面这个方法不是这个类原有的方法,是新增的。目的是用来判断这个用户是不是在训练数据集中存在
    def is_feature_index_exist(self, name):
        if name in self.feature_index_:
            return True
        else:
            return False
171

172
# ffm 格式转换函数、类
张彦钊's avatar
张彦钊 committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
# class FFMFormatPandas:
#     def __init__(self):
#         self.field_index_ = None
#         self.feature_index_ = None
#         self.y = None
#
#     def fit(self, df, y=None):
#         self.y = y
#         df_ffm = df[df.columns.difference([self.y])]
#         if self.field_index_ is None:
#             self.field_index_ = {col: i for i, col in enumerate(df_ffm)}
#
#         if self.feature_index_ is not None:
#             last_idx = max(list(self.feature_index_.values()))
#
#         if self.feature_index_ is None:
#             self.feature_index_ = dict()
#             last_idx = 0
#
#         for col in df.columns:
#             vals = df[col].unique()
#             for val in vals:
#                 if pd.isnull(val):
#                     continue
#                 name = '{}_{}'.format(col, val)
#                 if name not in self.feature_index_:
#                     self.feature_index_[name] = last_idx
#                     last_idx += 1
#             self.feature_index_[col] = last_idx
#             last_idx += 1
#         return self
#
#     def fit_transform(self, df, y=None):
#         self.fit(df, y)
#         return self.transform(df)
#
#     def transform_row_(self, row, t):
#         ffm = []
#         if self.y is not None:
#             ffm.append(str(row.loc[row.index == self.y][0]))
#         if self.y is None:
#             ffm.append(str(0))
#
#         for col, val in row.loc[row.index != self.y].to_dict().items():
#             col_type = t[col]
#             name = '{}_{}'.format(col, val)
#             if col_type.kind == 'O':
#                 ffm.append('{}:{}:1'.format(self.field_index_[col], self.feature_index_[name]))
#             elif col_type.kind == 'i':
#                 ffm.append('{}:{}:{}'.format(self.field_index_[col], self.feature_index_[col], val))
#         return ' '.join(ffm)
#
#     def transform(self, df):
#         t = df.dtypes.to_dict()
#         return pd.Series({idx: self.transform_row_(row, t) for idx, row in df.iterrows()})
#
#     # 下面这个方法不是这个类原有的方法,是新增的。目的是用来判断这个用户是不是在训练数据集中存在
#     def is_feature_index_exist(self, name):
#         if name in self.feature_index_:
#             return True
#         else:
#             return False