Skip to content

Latest commit

 

History

History
594 lines (453 loc) · 21.8 KB

分析思路和各种轮子.md

File metadata and controls

594 lines (453 loc) · 21.8 KB

查看各种版本

import sys #取得系统参数
print("Python_version: {}".format(sys.version))

import numpy as np
print("Numpy_version: {}".format(np.__version__))#取得Numpy版本

import pandas as pd
print("Pandas_version: {}".format(pd.__version__))#取得Pandas版本

import scipy as sp
print("Scipy_version: {}".format(sp.__version__))

import sklearn
print("Sklearn_version: {}".format(sklearn.__version__))

import IPython
from IPython import display #可以将jupyter_notebook里的dataframe变得外观更好看
Python_version: 3.7.4 (default, Aug  9 2019, 18:34:13) [MSC v.1915 64 bit (AMD64)]
Numpy_version: 1.16.5
Pandas_version: 0.25.1
Scipy_version: 1.3.1
Sklearn_version: 0.21.3

读取数据的方法

def read_write(read = True):
    if read :
        read_sty = 
              ["np.loadtxt(),具体见:理解amazon_main_xgboost文件",
               "pd.read_table(header = None)","np.load(allow_pickle)",
               "pd.read_csv(dtype = {},parse_dates =)",
               
               ]
    if write :
        write_sty = 
              ["with open() as f , f.write(),具体见:理解amazon_main_xgboost文件",
               "np.savetxt","np.save","file.to_csv(filename)"
                ]

预先对数据进行分析方法 & 模型技巧等汇总

def all_sty(pd = False,np = False,data_change = False
            ,pyt = True,dic = False,mat_sty = False,ot = False):
    """pd_sty用于存储pd相关的处理方法,dc_sty用于对改变数据的处理方法(如onehot)
       pyt用于存储python自带的处理方法,ot用于存储其他处理方法
       dic用于存储有关dictionary的方法"""
    pd_sty = {}
    np_sty = {}
    dc_sty = {}
    pyt_sty = {}
    dic_sty = {}
    ot_sty = {}
    if pd:        
        pd_sty = [".Series()",".info()",".value_counts",".corr()",".values",
                  ".sorted_values()",".hist()",".describe()",".isnull()",".notnull()",".isin()","df.sort_index()"
                  ".sort_values(by =col)",".apply(lambda..)",".rank(method)",
                  ".drop()",".dropna(subset)",".groupby(["A","B"],as_index = False)",".groupby(..).agg({"C":["sum","mean"]})",
                  ".unique()",".get_indexer",
                  "fillna()",".count()",".columns()",".iloc[]",".date_range","df1.join(df2,on = ,how = )"
                  ".merge()",".head()",".set_index",".cut()",".from_dict()",
                  "pd.where(注意与np.where的不同)","pd.plotting.scatter_matrix()",".reset_index()",
                  ".drop_duplicates()",".nunique()","to_datetime()","datetime.dt()",
                  ".reset_index()","idxmax()",".var()",".sample()","pd.DatetimeIndex()","datetime.momth(year,day)"
                  ".cross_tab()",".mode(),不是取模,是取得每行(列)出现频率最高的值",
                  ".cut()",".qcut()",".intersection()",
                  "pd.get_dummies(df),可以自动将df中所有字符串特征onehot,数值型特征保持不动",
                  "pd.melt()",".clip()","df.select_dtypes",
                  "df.query()","df.at[]",".product()","df.iterrows()","column.astype()",".reset_index()重新得到按顺序的index"
                   ]
    if np:
        np_sty = [".mean()",".std()",".ceil()",".arange()","np.linspace()","np.repeat()"
                  ".floor()",".c_[]","._r[]",".max()",".asarray()",
                  "np.where(注意与pd.where的不同)","np.isnan()",
                  ".vstack()",".hstack()",".sqrt()",
                  "mat()",".zeros()",".ones()",".pi",".random.permutation()",
                  ".random.randn(a,b)",".random.normal()",".array(data,dtype)",".fill()",
                 ".ones_like",".zeros_like()",".eye()",".empty()",
                  ".reshape()","矩阵乘法:@/.dot/.matmul","矩阵同位置元素相乘:a*b",
                  ".subtract()","np.meshgrid",".cumprod()",".cumsum()",
                 ".any()",".all()","np.sort()",
                  ".argmax(),返回该数组最大值的索引,当有相等的最大值的时候,返回第一个出现的最大值的索引",
                  ".abs()",".var(ddof = )",".clip()"
                 ]
        
    if data_change:
        dc_sty = ["StandardScaler()","imputer","log",
                 "onehot",]
    
    if pyt:
        pyt_sty ={"str_f":
                  ["str.count()",".title()",".upper()",
                   ".lower()",".rstrip()",".lstrip()",
                   ".strip()","+",".split()",".map()"],
                  
                  "list_f":
                  ["list()",".append()",".insert()","del()",
                    ".pop()",".remove()",".sort()",".reverse(),会修改原数据","[::-1]"
                   "sorted()","[:]",".copy()","list1.extend(list2)"],
                  
                  "change_f":
                  ["int()","float()","str()"],
                  
                  "other_f":
                  ["range()","切片","set()","\t,\n","取整://,取模:%",
                   ,".intersection()",".dtype","type()",
                   "data.plot(kind = 图的类型,x,y,,alpha = 透明度),还有label,s(散点大小),c(散点颜色),cmap,colorbar等参数,见机器学习实战p58"
                  "isinstance(a,type)",".count()",".copy()"]
                 }
    
    if dic:
        dic_sty = {
            iter_f:[".items()",".keys()",".values()",".update()","pd.DataFrame.from_dict()",
                    "del dict['key']","dict.clear()","del.dict"],
        }
        
    if matplib:
        mat_sty = ["pyplot.scatter()",]
    
    if ot:
        ot_sty = { "play_data":
                  ["按取值范围分桶(见taitanic中技巧)",
                   "StratifiedShuffleSplit(分层抽样,见taitanic模型),注意与直接使用train_test_split的不同",
                   "保存训练好模型的方法:sklearn.externals 的 joblib类,具体见amazon_stacking主文件",
                   "GridSearchCV(见titanic模型)","cross_val_score(见titanic模型)",
                "cross_val_predict(),为每个样本得到相对干净的预测,注意使用的时候,不同的分类器可能是不同的method,分类问题一般是predict_proba",
                   "RandomSearchCV(见titanic模型,以及机器学习实战homework文件夹的总结txt)",
                   "[:]","confusion_matrix()"],
                  
                  "circle_data":
                  ["while/for : activate,break,continue,in/not in ,enumerate ",
                   "try_except","try_except_else","zip()","max_iters",
                   "early_stopping",],
                  
                   "other_f" :
                  ["unittest","判断收集数据时是否存在上下限","clone",
                   "csr_matrix(),压缩稀疏矩阵,加快计算速度"
                   "f1,roc",
                   "模拟退火&学习计划""pca&pca后可视化",
                   "time: sleep()",
                   "model通常在循环中设置新的seed,以便拟合多次模型求均值",
                   "特征交互,关于构建交互项,具体见amanzon_stacking中的理解其他模型",
                   "Counter()"
                   
                  ]
                 }
    return pd_sty, np_sty, dc_sty, pyt_sty, dic_sty,mat_sty, ot_sty

选择AUC还是PR


二分类问题里的观察模型好坏的经验法则: 如果样本的正类相对非常少或者问题更加关注假阳性(担心检验的出错,如给小孩子判断是否适合看的视频,需要门槛高,假阳性率很低)而不是假阴性, 那么就适合使用PR曲线,否则就使用ROC曲线。


可以使用sklearn.metrics的roc_curve方法直接得到特定预测结果在不同阈值下的fpr,tpr,阈值,可以用这些数据画出roc图像(具体见机器学习实战p90-91) roc_auc_score方法则可以直接得到特定预测结果的auc值(0.5为纯随机分类器)

使用sklearn.metrics的precision_recall_curve方法则可以得到特定预测结果在不同阈值下的precision,recall,可以用这些数据画出PR图像(具体见机器学习实战p88-89)

直接计算特定预测结果的精度和召回率,可以使用sklearn.metrics的precision_score和recall_score两个方法

还可以将不同的模型得到的pr或者roc线放在一张图例做对比(具体见机器学习实战p90-p92)

#自己写的计算召回率recall和假阳性率fpr的函数

"""ypred为预测类别,yval为真实类别"""
def recall_fd(y_pred,y_val):
    ones_val = []
    zeros_val = []
    ones_model = []
    zeros_model = []
    #num为统计召回率个数,num2为统计假阳性个数
    num = 0
    num2 = 0
    for i in range(len(y_val)):
        """存储y_val中label为1和label为0的索引"""
        if y_val.iloc[i] == 0:
            zeros_val.append(i)
        else:
            ones_val.append(i)
            
    for i in range(len(y_pred)):
        """存储y_pred中label为1和label为0的索引"""
        if y_pred[i] == 0:
            zeros_model.append(i)
        else:
            ones_model.append(i)
            
    for i in range(len(ones_model)):
        """计算召回个数"""
        if ones_model[i] in ones_val:
            num += 1
    for i in range(len(ones_model)):
        """计算假阳性个数"""
        if ones_model[i] in zeros_val:
            num2 += 1

    #计算假阳性率还有召回率
    recall_rate = num/len(ones_val)
    false_dis = num2/len(ones_model)
    return recall_rate,false_dis

预处理数据使用的Pipeline

#预处理的pipeline
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder,StandardScaler
from sklearn.compose import ColumnTransformer

#处理na值然后标准化
num_tra_pipe = Pipeline([
    ("imputer",SimpleImputer(strategy = "mean")),
    ("sta_sca",StandardScaler()),    
])

#对离散特征进行onehot
cat_tra_pipe = Pipeline([
    ("imputer",SimpleImputer(strategy = "most_frequent",missing_values = np.nan)),
    ("oh",OneHotEncoder(sparse = False)),
])

#数字型特征列表
num = []
#离散型特征列表
cat = []

#制作一个函数,可以用来处理数字型特征的na值,标准化,以及onehot离散型数据
def attr_tra(data,num_att,cat_att):
    """data是指待转换数据集
       num_att为数字型特征列表,
       cat_att为离散型特征列表"""
    full_pipe = ColumnTransformer([
    ("num_tra",num_tra_pipe1,num_att),
    ("cat_tra",cat_tra_pipe,cat_att),
    ])
    data_tra = full_pipe.fit_transform(data)
    return data_tra

时间序列数据的特征提取:

类别型数据

#类别型的相关函数:

#返回每个样本下的总个数(包括所有类别)
def sample_sum(data,cat_name,group_by):
    """使用前提,样本的id(或者类似标注)已是这个data的索引"""
    sample_sum = data[cat_name].groupby(group_by).count()
    col_name = cat_name + "_sample_sum" 
    sample_sum = pd.Series(sample_sum,name = col_name)
    return sample_sum
    
#返回每个样本下出现了哪些类别(种类数)
def sample_cat_sum(data,cat_name,group_by):
    """使用前提,样本的id(或者类似标注)已是这个data的索引"""
    data_temp = data.reset_index()
    unique_beh = data_temp[[group_by,cat_name]].drop_duplicates()
    sample_cat_sum = unique_beh.set_index([group_by])
    col_name = cat_name + "sample_cat_sum"
    sample_cat_sum.columns = [col_name]
    sample_cat_sum = sample_cat_sum.groupby(group_by).count()
    return sample_cat_sum

#返回每个样本出现类别的众数
def cat_most_fre(data,cat_name,group_by):
    """使用前提,样本的id(或者类似标注)是已是这个data的索引
       当连接到总数据的时候,没有众数的样本为None"""
    index_num = np.unique(data.index)
    cat_dict = {}

    for num in index_num:
        cat = pd.Series(data.loc[num][cat_name])
        most_fre = cat.value_counts().index[0]
        dict_temp = {num : most_fre}
        cat_dict.update(dict_temp)
    
    cat_most_fre = pd.DataFrame.from_dict(cat_dict,orient = "index")
    col_name = cat_name + "_most_fre"
    cat_most_fre.columns = [col_name]    
    return cat_most_fre

#返回每个样本各个类别各自出现次数
def cat_each_sum(data,cat_name,group_by,link_data):
    """使用前提,样本的id(或者类似标注)已是这个data的索引"""
    cat_value = data[cat_name].value_counts().index
    each_cat_num = []

    for value in cat_value:
        #不同的value具有不同长度的列,因为不同的样本有不同的类别
        temp = data[data[cat_name] == value][cat_name].groupby(group_by).count()
        col_name =cat_name+"_"+str(value)+"_num"
        temp_series = pd.Series(temp,name = col_name)
        each_cat_num.append(temp_series)
    
    for i in range(len(each_cat_num)):
        link_data = pd.merge(link_data,each_cat_num[i],how = "outer",left_index = True,right_index = True).fillna(0)
    return link_data

#使用例子(具体见Fin-tec项目Fin-tec的文件):
cat_att = ["Dat_Flg1_Cd","Dat_Flg3_Cd","Trx_Cod1_Cd","Trx_Cod2_Cd"] #该时间序列数据中类别型特征的名字,这里有四个
link_data = pd.DataFrame(index = data_tag.index) #所有id,作为一个初始的Dataframe
data = data_trd #准备处理特征所在的时间序列数据
group_by = "id" #样本的id(即key,键属性)
cat_df_set = [] #用于存储每个特征提取的新特征形成的表,这里四个特征,会产生四个表
for cat in cat_att:
    cat_df = cat_each_sum(data,cat,group_by,link_data)
    temp1 = sample_sum(data,cat,group_by)
    temp2 = sample_cat_sum(data,cat,group_by)
    temp3 = cat_most_fre(data,cat,group_by)
    cat_df = pd.merge(cat_df,temp1,how = "outer",left_index = True,right_index = True).fillna(0)
    cat_df = pd.merge(cat_df,temp2,how = "outer",left_index = True,right_index = True).fillna(0)
    cat_df = pd.merge(cat_df,temp3,how = "outer",left_index = True,right_index = True).fillna("None")
    #None表示没有众数,可能是时间序列数据里没有出现这个id
    cat_df_set.append(cat_df)  

#最后把这四个表连接起来,就是这个训练数据里时间序列数据里类别型特征所提取的新特征,注意可能和测试数据的提取到的特征有所不同,详见项目总结
trd_cat_data = pd.merge(cat_df_set[0],cat_df_set[1],left_index = True,right_index = True)
trd_cat_data = pd.merge(trd_cat_data,cat_df_set[2],left_index = True,right_index = True)
trd_cat_data = pd.merge(trd_cat_data,cat_df_set[3],left_index = True,right_index = True)
#方差,均值,极大值极小值,中位数
met = ["var","mean","min","max","median"]
#样本的id(即key,键属性)
group_by = "id"
#准备处理特征所在的时间序列数据
data = data_trd
#该时间序列数据中数字型特征的名字,这里有一个
num_att = "cny_trx_amt"

def num_attr_stat(data,num_att,group_by,met):
    if met == "var":
        attr_stat = data[num_att].groupby(group_by).var()
        attr_stat = pd.Series(attr_stat,name = num_att+"_"+met)
    elif met == "mean":
        attr_stat = data[num_att].groupby(group_by).mean()
        attr_stat = pd.Series(attr_stat,name = num_att+"_"+met)
    elif met == "min":
        attr_stat = data[num_att].groupby(group_by).min()
        attr_stat = pd.Series(attr_stat,name = num_att+"_"+met)
    elif met == "max":
        attr_stat = data[num_att].groupby(group_by).max()
        attr_stat = pd.Series(attr_stat,name = num_att+"_"+met)
    elif met == "median":
        attr_stat = data[num_att].groupby(group_by).median()
        attr_stat = pd.Series(attr_stat,name = num_att+"_"+met)       
    return attr_stat

link_data = pd.DataFrame(index = data_tag.index)#所有id,作为一个初始的Dataframe

#生成新特征且将这些新特征连接到一起
for m in met:
    temp = num_attr_stat(data,num_att,group_by,m)
    link_data = pd.merge(link_data,temp,how = "outer", left_index = True,right_index = True).fillna(0)
trd_num_data = link_data[:]

补充:

具体操作可见predict_future_sales项目的代码

1.使用shift方法将特征向前后移动产生新特征或者因变量,注意,mean_encode出来的特征也可以用来shift

2.使用window方法(类似均线),对近期的特征求统计量(均值,最值等等),获得特征

3.求某特征的trend,即一段时间内的变化百分比(相对于均值或者其他参考对象)具体可见kaggle的notebook笔记:Feature engineering, xgboost

4.mean_encoding

常用产生随机数:使用模块random

import random

print(random.normalvariate(5,10)) #打印一个来自均值为5,标准差为10的正态分布的随机变量
print(random.randint(1,10)) #返回一个整数来1~10的整数
print(random.random()) #返回一个0~1之间的数
print(random.uniform(1.2,5.3)) #返回一个来自于区间(1.2,5.3)均匀分布内的值,区间可以不是整数
print(random.choice("tomorrow"))#返回序列中随机一个元素
print(random.randrange(1,100,2)) #生成1~100间隔为2的序列中的一个随机整数
print(random.randrange(0,101,2)) #生成了0~100中的随机一个偶数
print(random.sample('zyxwvutsrqponmlkjihgfedcba',5)) #选取序列中随机5个元素

a = [1,3,5,6,7] 
random.shuffle(a) #将a中的顺序打乱(直接改变了a),可以用来产生验证数据或者测试数据
print(a)
8.029069112216682
6
0.25043290601587964
2.6754265742279286
o
49
32
['b', 'l', 'y', 'h', 'p']
[5, 3, 6, 1, 7]

根据分类的类别画直方图

#具体使用例子见Coursera_Note里面的supplementary notebook第一周的GBM_drop_tree
#直方较少的版本
def hist_it(feat,Y):
    """feat为指定要画hist的特征列。Y为target列,取值为0或者1。
    hist的normed参数表示经过标准化直方图和为1。
    这个图分别画了0和1的在这个特征下的分布,
    可以帮助我们看到这个特征的哪些值域可以更好地区分target"""
    plt.figure(figsize=(16,4))
    feat[Y==0].hist(bins=range(int(feat.min()),int(feat.max()+2)),normed=True,alpha=0.8)
    feat[Y==1].hist(bins=range(int(feat.min()),int(feat.max()+2)),normed=True,alpha=0.5)
    plt.ylim((0,1))
    
#直方比较多的版本(更加密集)
def hist_it_more(feat,Y):
    plt.figure(figsize=(16,4))
    feat[Y==0].hist(bins=100,range=(feat.min(),feat.max()),normed=True,alpha=0.5)
    feat[Y==1].hist(bins=100,range=(feat.min(),feat.max()),normed=True,alpha=0.5)
    plt.ylim((0,1))
#具体使用例子见
#https://www.kaggle.com/ldfreeman3/a-data-science-framework-to-achieve-99-accuracy/data#Step-4:-Perform-Exploratory-Analysis-with-Statistics
plt.subplot(234)#表示接下来要画在2x3共6张图的布局中,第二行第一张图

plt.hist(x = [data1[data1['Survived']==1]['Fare'], data1[data1['Survived']==0]['Fare']], 
         stacked=True, color = ['g','r'],label = ['Survived','Dead'])
plt.title('Fare Histogram by Survival')
plt.xlabel('Fare ($)')
plt.ylabel('# of Passengers')
plt.legend()

批量获取分类变量和因变量y之间的联系(求统计量)

#data1_x存储列名
#对于data1中的那些列,如果不是float类型,即是类别变量,则批量使用groupby和因变量y值进行求统计量(在这里是求不同类别的y均值)

for x in data1_x:
    if data1[x].dtype != 'float64' :
        print('Survival Correlation by:', x)
        print(data1[[x, Target[0]]].groupby(x, as_index=False).mean())
        print('-'*10, '\n')

map的使用

Label Encode

#伪代码
fea_value = df[fea].unique()
fea_value_index = range(df[fea].nunique())
#一个fea对应一个新index(0到nunique)
fea_dict = dict(zip(fea_value, fea_value_index))

#将原类别特征的类别转换为新值
df[fea] = df[fea].map(fea_dict)

value_counts

#伪代码
#将fea每个类别的数目汇总,形成新特征
fea_value_counts = df[fea].value_counts()
df[fea + "_count"] = df[fea].map(fea_value_counts)

apply的使用

dict的常见使用方式

字符串的处理

join,concat和merge的常见使用方式

其他技巧:

#gc库:
    删除临时变量用于训练前腾出空间del 变量名
    再使用gc()


#joblib库:
    使用joblib库的joblib.dump保存模型类型为pkl使用joblib.load读取模型


#让matplotlib的图片正常显示中文:
    可能需要下载'SimHei'图片库
    plt.rcParams['font.sans-serif'] = ['SimHei']


#使用as.type(int),可以直接将bool值转换成0,1


#使用pd.get_dummies("feature",prefix = "feature"),可以直接获得该特征所有样本的onehot表格


#gropuby的常见使用(易混淆)
(伪代码,且以统计量count作为例子其他统计量类似):
    pd.groupby(["A","B"])[fea].count()
    pd.groupby(["A","B"])[fea].agg({fea:["count"]})
    pd.groupby(["A","B"])[fea].transform("count")
注意三者的不同前两者出来的结果类似都是汇总表类似value_counts常搭配reset_index()使用
第三个transform是前两者更进一步将前两者得到的value_counts对应原数据代入每个样本后得到的结果新特征#for循环的时候,常使用tqdm库(或者该库的tqdm notebook)对循环进度进行可视化


#将pandas的Series快速转换为DataFrame
    对于id有名称而值无名称的的series使用Series.reset_index(name = "a") 
    就可以得到一个新的dataframe
    其中第一列是原本series的id且列名为id名第二列为原先series的值且列名为a#jupyter notebook中使用魔术代码记录代码的运行时间

    %%time    #开头
    ...
    ...(具体代码)
    ...
    print()    #结尾

备注%%time这一行命令一定要放在最开头代码框的开头