人工智能发展必备三要素:数据、算法、计算力
人工智能和机器学习,深度学习的关系:
机器学习概述:从数据中自动分析获取模型,并利用模型对未知数据进行预测
需要安装:scikit-learn
scikit-learn 官方文档
机器学习工作流程总结:
数据处理和特征工程决定了机器学习的上限,而模型训练和优质算法只是为了逼近这个上限
我们的数据大部分存在于文件当中,所以pandas
会支持复杂的IO
操作,pandas
的API
支持众多的文件格式,例如CSV
,SQL
,XLS
,JSON
,HDF5
。
注:最常用的HDF5
和CSV
文件
读取CSV
数据
pandas.read_csv(filepath_or_buffer,sep =',',usecols=[])
filepath_or_buffer
:文件路径(相对路径和绝对路径均可使用)sep
:分隔符,默认用,
usecols=[]
:指定读取的列名,列表形式chunksize
:分批加载,每次加载的多少条数据iterator
:读取的数据 呈 可迭代类型 输出(可遍历)保存数据为 CSV
文件
DataFrame对象名.to_csv(path_or_buf=None, sep=', ’, columns=None, header=True, index=True, mode='w', encoding=None)
path_or_buf
:文件路径sep
:分隔符,默认用,
columns
:选择需要写入文件的列索引名header
:是否写入列索引,布尔值或字符串列表,默认为True
,index
:是否写入 行索引,False
为不写入行索引;读取时会将其当做一列数据而非列索引mode
:写入方式 。w
:删除原文件数据写入,a
追加写入需要安装安装tables
模块,否则不能读取HDF5
文件
pip install tables
HDF5
文件可以保存多张表,因此读取和存储需要指定一个key
来 标识 DataFrom
读取格式:pandas.read_hdf(path_or_buf,key =None,** kwargs)
保存格式:pandas.to_hdf(path_or_buf,key =None,** kwargs)
path_or_buffer
:文件路径key
:保存和读取时 用来标识DataFrom
的键return
:Theselected object
注意:优先选择使用HDF5
文件存储
HDF5
在存储的时候支持压缩,使用的方式是blosc
pandas
默认支持的HDF5
还是跨平台的,可以轻松迁移到hadoop
上面pandas.read_json(path_or_buf=None, orient=None, typ='frame', lines=False)
将JSON
格式准换成默认的Pandas DataFrame
格式
orient
: string
,Indication of expected JSON string format
split
: dict like {index -> [index], columns -> [columns], data -> [values]}
split 将索引总结到索引,列名到列名,数据到数据。将三部分都分开了
s='{"index":["stu1", "stu2", "stu3"],'\
'"columns":["name","age"],'\
'"data":[["xiaomaimiao", 20],["xxt", 18],["xmm", 1]]'\
'}'
print(pd.read_json(s,orient='split'))
执行结果:
age name
stu1 20 xiaomaimiao
stu2 18 xxt
stu3 1 xmm
records
: list like [{column:value}, ... , {column:value}]
最常规
s='[{"name":"xiaomaimiao","age":20},'\
'{"name":"xxt","age":18},'\
'{"name":"xmm","age":1}]'
print(pd.read_json(s,orient='records'))
执行结果:
age name
0 20 xiaomaimiao
1 18 xxt
2 1 xmm
index
: index: {columns:values, ...}...
s='{"stu1":{"name": "xiaomaimiao", "age":20},'\
'"stu2":{"name": "xxt", "age": 18},'\
'"stu3":{"name": "xmm", "age": 1},}'
print(pd.read_json(s,orient='index'))
执行结果:
age name
stu1 20 xiaomaimiao
stu2 18 xxt
stu3 1 xmm
columns
: columns: {index:values,...}
s='{"name":{"stu1": "xiaomaimiao", "stu2": "xxt", "stu3": "xmm"},'\
'"age":{"stu1": 20, "stu2": 18 "stu3": 1}}'
print(pd.read_json(s,orient='columns'))
执行结果:
name age
stu1 xiaomaimiao 20
stu2 xxt 18
stu3 xmm 1
values
: just the values array
values
直接输出值
s='[["a",1],["b",2]]'
print(pd.read_json(s,orient='values'))
执行结果:
0 1
0 a 1
1 b 2
lines
: boolean, 默认False
按照每行读取json
对象,json
与DataFrom
行行对应
typ
: 默认 ‘frame’
, 指定转换成的对象类型series
或者dataframe
DataFrame.to_json(path_or_buf=None, orient=None, lines=False)
Pandas
对象存储为json
格式path_or_buf=None
:文件地址orient
:存储的json
形式,{‘split’,’records’,’index’,’columns’,’values’}
lines
:一个对象存储为一行算法中的数据一般以 数据集的形式存在:
根据数据集中是否包含目标值和目标值类型分为:
RDD的程序入口
1. 导入pyspark库中的SparkContext类
from pyspark import SparkContext
2. 创建SparkContext实例,并设置Spark应用的基本信息
sc = sparkContext('local','test')
源码:pyspark.SparkContext(master = None,appName = None,sparkHome = None,pyFiles = None,environment = None,batchSize = 0,
serializer = PickleSerializer(),conf = None,gateway = None,jsc = None,
profiler_cls = )
参数:master:要连接的群集URL (例如:mesos:// host:port,spark:// host:port,local [4])
appName:您的工作的名称,将显示在群集Web UI上。
sparkHome:在群集节点上安装Spark的位置。
pyFiles:.zip或.py文件的集合,以发送到集群并添加到PYTHONPATH
这些可以是本地文件系统或HDFS,HTTP,HTTPS或FTP URL上的路径。
environment:在工作节点上设置的环境变量字典
batchSize:表示为单个的Python对象的数量Java对象。
设置1禁用批处理,
设置0以根据对象大小自动选择批处理大小
设置-1以使用无限的 批处理大小
serializer :RDD的序列化器。
conf:AL {SparkConf}对象设置Spark属性。
gateway:使用现有的网关和JVM,否则将实例化新的JVM
jsc:JavaSparkContext实例(可选)。
profiler_cls:一类用于进行概要分析的自定义Profiler
(默认为pyspark.profiler.BasicProfiler)。
DataForm的程序入口
4. 导入pyspark库中的SparkSession类
from pyspark.sql import SparkSession
5. 创建sparkSession实例,并设置Spark应用的基本信息
sparkSession实例名 = SparkSession.builder.appName("xxx").getOrCreate()
类方法:
.appName:工作名称,将显示在群集 Spark Web UI上( host:4040 )
.getOrCreate():获取一个现有的SparkSession,如果不存在,则根据此构建器中设置的选项创建一个新的。
.config(key = None,value = None,conf = None ):设置配置选项
使用此方法设置的选项会自动传播到SparkConf和SparkSession自己的配置中。
.enableHiveSupport():启用Hive支持,包括与持久性Hive Metastore的连接,对Hive Serdes的支持以及Hive用户定义的功能。
.master:要连接的群集URL (例如,mesos:// host:port,spark:// host:port,local [4])
传入local代表本地模式, local[4]代表本地模式4内核运行 , 或者spark://master:7077 提交到 standalone集群模式运行
创建成RDD
由本地或HDFS
文件创建
# 读取本地文件
sparkContext实例名.textFile("file:///xxx/xxx.txt") # sc为创建的sparkcontext对象
# 读取本地压缩包
sparkContext实例名.textFile("file:///xxx/xxx.gz")
# 读取hdfs的上的文件
sparkContext实例名.textFile("hdfs://node-teach:8020/xxx/xxx.log")
支持整个目录、多文件、通配符
集合并行化:把非RDD
数据转换为RDD
SparkContext
的 parallelize
方法 将 现有的可迭代对象或者集合 转化# 定义一个列表,并将列表序列化为 RDD
data=[1,2,3,4,5]
rdd1 = sparkContext实例名.parallelize(data, 指定分区数量)
CPU核数
指定(每个CPU核
有2-4个分区)Spark
会自动设置分区(CPU核数*2
)创建 DataFrom
基于本地RDD、csv、json、parquet、orc、jdbc
文件,通过sparkSession.read.数据源格式.local(数据源文件名)
生成
# 基于 Java文件 生成 (两种方法,两种书写方法)
方法一:反射自动推测,适合静态数据
jsonDF = sparkSession实例名.read.json("xxx.json")
jsonDF = sparkSession实例名.read.format('json').load('xxx.json')
方法二:程序指定,适合程序运行中动态生成的数据
from pyspark.sql.types import StructType, StructField
# 根据json的具体数据类型指定DataFrom的Schema(两种写法)
jsonSchema = StructType() \ # StructType表示的是一个对象,在json中的体现为 大括号 {}
.add("id", StringType(),True) \ # (json中的键,该键对应值的数据类型,是否为空)
.add("city", StringType()) \
.add("pop" , LongType()) \
.add("state",StringType())
jsonSchema = StructType([
StructField("id", StringType(), True),
StructField("city", StringType(), True),
StructField("loc" , ArrayType(DoubleType())), # 表示 键loc值的数据类型为数组,并且数组中的元素为 Double类型(双精度小数)
StructField("pop", LongType(), True),
StructField("state", StringType(), True)
])
jsonSchema = StructType() \ # 有嵌套类型的json
.add("dc_id", StringType()) \
.add("source", MapType(StringType(), # 表示 键source值中嵌套了几个并列的json,其中嵌套json的键数据类型为StringType,值为StructType(......)
StructType() \
.add("description", StringType()) \
.add("ip", StringType()) \
.add("id", LongType()) \
.add("geo", StructType() \ # 表示 键geo值中嵌套了一个json
.add("lat", DoubleType()) \
.add("long", DoubleType())
)
)
)
jsonDF = sparkSession实例名.read.schema(jsonSchema).format('json').load('xxx.json')
# json字符串的解析
explodedDF = jsonDF.select("dc_id",explode("source")) # explode("source") 表示 获取 source嵌套json内部的 key 和 value
notifydevicesDS = explodedDF.select( "dc_id", "key",
explodedDF.value.getItem("id") ,explodedDF.value['temp'].alias('为列起别名') ) # 通过value.getItem(键名)或 value[键名] 进一步取指定值
# 基于csv文件 创建
CSVdf = sparkSession实例名.read.csv("hdfs://IP:9000/csv文件名.csv", header=True, schema=schema) # 读取CSV文件中保存的json
CSVdf = sparkSession实例名.read.format("csv"). option("header", "true") .load("csv文件名.csv")
方法:
.format(数据源格式):指定输入数据源格式
.load(path = 指定文件路径列表,format = None,schema = None,** options ):从数据源加载数据,并将其作为:class`DataFrame`返回
.option(key,value):为基础数据源添加输出选项
# 基于mysql数据库
jdbcDF = sparkSession实例名.read.format("jdbc")
.option("url","jdbc:mysql://localhost:3306/数据库名") # 数据库的主句IP,端口 和数据库名
.option("dbtable","表名") # 连接的表名
.option("user","用户名") # 用户名
.option("password","密码") # 密码
.load()
注意:若是将DataFrom保存成相应的数据类型 仅需将 read 改成 save
基于已有的pandas dataframe、list、RDD
,通过sparkSession.createDataFrame
生成
# 基于RDD创建
sc = sparkContext('local','test')
l = [('Ankit',25),('Jalfaizy',22),('saurabh',20),('Bala',26)]
rdd = sc.parallelize(l)
方法1
# 为数据添加列名
people = rdd.map(lambda x: Row(name=x[0], age=int(x[1])))
# 创建DataFrame
schemaPeople = sparkSession实例名.createDataFrame(people)
方法2
# 定义Schema
from pyspark.sql.types import StructType ,structField
schema = StructType (structField ("字段名", 数据类型, 能否为空),structField ("name", stringType (), True),structField("age", LongType (), True)
# 创建DataFrom
swimmers = sparkSession实例名.createDataRrame (stringCSVRDD, schema)
作用:对数据中的缺失值、异常值 和 重复值 进行 补全、替换 或 删除 等处理
pandas
dataframe.duplicated() # 判断该数据记录是否重复(返回 True 和 False)
dataframe.drop_duplicates([指定列的列表]) # 删除数据记录中指定列列值都相同的记录
spark
格式:datafrom.dropDuplicates(字段列表) 表示删除字段列表中的值完全一致的重复行
1. 删除完全一样的记录
df1 = df.dropDuplicates()
2. 删除关键字段值完全一致的记录(例:删除 除id 外 其余值一致的数据)
df2 = df1.dropDuplicates(subset = [c for c in df2.columns if c!='id'])
3. 查看某一列是否有重复值
import pyspark.sql.functions as fn
df2.agg(fn.count('id').alias('id_count'),fn.countDistinct('id').alias('distinct_id_count')).collect()
对于id这种无意义的列重复,添加另外一列自增id
df2.withColumn('new_id',fn.monotonically_increasing_id()).show()
缺失值处理方式
pandas
1. 获取缺失值的标记方式( NaN 或 其他标记方式)
将其他标记的缺失值替换成 NaN : .replace(to_replace='?', value=np.nan)
2. 判断是否含有缺失值数据
1. pd.isnull(DataFrame对象名) 配合 np.any()使用( pd.isnull().any())
配合`sun()`直接获取字段空值个数`pd.isnull().sum()`
2. pd.notnull(DataFrame对象名) 配合 np.all()使用
3. pd[(DataFrame对象名)=="其他标记符号"] 配合 np.any()使用
4. 1 - (DataFrame对象名.count()/DataFrame对象名.shape[0]) 查看列缺失比例
5. 绘制行缺失比例个数条形图
h_nan = 1 - (DataFrame对象名.count(1)/DataFrame对象名.shape[1])
h_nan.groupby(h_nan.values).count().plot.bar()
3. 处理缺失值
1. 删除缺失值少于指定非缺失值个数的行和列:dropna(axis ='rows', thresh=非缺失值个数) axis =1 表示删除列,默认为删除行
注:不会修改原数据,需要接受返回值
2. 替换缺失值:fillna(value,inplace = True, method='backfill')
value: 替换成的值
inplace:True:会修改原数据,False:不替换修改原数据,生成新的对象
method:表示填充方式
backfill:用后面的值替换缺失值
bfill, limit=1: 用后面的值替代缺失值,限制每列只能替代一个缺失值,当连续出现NAN时,填充后仍会包含NAN
pad:用前面的值替换缺失值
{'col2': 1.1, 'col4': 1.2}: 用不同值替换不同列的缺失值
.fillna(df.mean()['col2':'col4']) :选择各自列的均值替换缺失值
使用sklearn
填充缺失值
from sklearn.impute import SimpleImputer # 导入sklearn中SimpleImputer库
nan_model = SimpleImputer(missing_values=np.nan, strategy='mean') # 建立替换规则:将值为NaN的缺失值以均值做替换
nan_result = nan_model.fit_transform(df) # 应用模型规则
spark
df_miss = spark.createDataFrame([
(1, 143.5, 5.6, 28,'M', 100000),
(2, 167.2, 5.4, 45,'M', None),
(3, None , 5.2, None, None, None),
(4, 144.5, 5.9, 33, 'M', None),
(5, 133.2, 5.7, 54, 'F', None),
(6, 124.1, 5.2, None, 'F', None),
(7, 129.2, 5.3, 42, 'M', 76000),],
['id', 'weight', 'height', 'age', 'gender', 'income'])
1. 计算各列的缺失情况百分比
df_miss.agg(*[(1 - (fn.count(c) / fn.count('*'))).alias(c + '_missing') for c in df_miss.columns]).show()
2. 删除缺失值过于严重的列
df_miss_no_income = df_miss.drop('列1')
3. 计算每行记录的缺失值情况
df_miss.rdd.map(lambda row:(row['id'],sum([c==None for c in row]))).collect()
[(1, 0), (2, 1), (3, 4), (4, 1), (5, 1), (6, 2), (7, 0)]
4. 按照 非缺失值个数 删除行
df_miss_no_income.dropna(thresh=3).show()
5. 填充缺失值,可以用fillna来填充缺失值,
# 对于数值类型,可以用均值或者中位数等填充
# 先计算均值,并组织成一个字典
means = df_miss_no_income.agg( *[fn.mean(c).alias(c) for c in df_miss_no_income.columns if c != 'gender']).toPandas().to_dict('records')[0]
# 对于bool类型、或者分类类型,可以为缺失值单独设置一个类型,missing
means['gender'] = 'missing'
# 根据字典修改缺失值
df_miss_no_income.fillna(means).show()
异常值:不属于正常的值
包含:超过正常范围内的较大值或较小值
方法:分位数去极值、中位数绝对偏差去极值、正态分布去极值
核心思想:通过原始数据设定一个正常的范围,超过此范围的就是一个异常值
异常值(极值)处理:
pandas
的 Z-Score
去极值
计算公式 Z = X-μ/σ
其中μ
为总体平均值,X-μ
为离均差,σ
表示标准差。z
的绝对值表示在标准差范围内的原始分数与总体均值之间的距离。当原始分数低于平均值时,z
为负,以上为正
df = pd.DataFrame({'col1': [1, 120, 3, 5, 2, 12, 13],
'col2': [12, 17, 31, 53, 22, 32, 43]})
# 通过Z-Score方法判断异常值
z_score = (df - df.mean()) / df.std() # 计算每列的Z-score得分
df_zscore = z_score.abs() < 2.2 # 判断Z-score得分是否大于2.2,如果是则是True,否则为False
# 删除异常值所在的行
df_drop_outlier = df[df_zscore].dropna() # 取出df_zscore中为True的数据,为False的数据变成 NaN;之后删除含NAN的行
# 一行代码表示
df_drop_outlier = df[((df - df.mean())/df.std()).abs()<2.2].dropna()
pandas
分位数去极值
# 构建数据
df_outliers = pd.DataFrame([
(1, 143.5, 5.3, 28),
(2, 154.2, 5.5, 45),
(3, 342.3, 5.1, 99),
(4, 144.5, 5.5, 33),
(5, 133.2, 5.4, 54),
(6, 124.1, 5.1, 21),
(7, 129.2, 5.3, 42),
], columns=['id', 'weight', 'height', 'age'])
# 设置行索引
df = df_outliers.set_index("id")
# 根据四分位数计算出内距
df_ = df.describe().loc[["25%", "75%"],:].T
df_["min"] = df_["25%"] - 1.5 * (df_["75%"] - df_["25%"])
df_["max"] = df_["75%"] + 1.5 * (df_["75%"] - df_["25%"])
# 删除不在内距中的异常值
df[(df >= df_["min"]) & (df <= df_["max"])].dropna()
spark
分位数去极值
df_outliers = spark.createDataFrame([
(1, 143.5, 5.3, 28),
(2, 154.2, 5.5, 45),
(3, 342.3, 5.1, 99),
(4, 144.5, 5.5, 33),
(5, 133.2, 5.4, 54),
(6, 124.1, 5.1, 21),
(7, 129.2, 5.3, 42),
], ['id', 'weight', 'height', 'age'])
# 设定范围 超出这个范围的 用边界值替换
# approxQuantile方法计算分位数,接收三个参数:参数1,列名;参数2:想要计算的分位点,可以是一个点,也可以是一个列表(0和1之间的小数),
第三个参数是能容忍的误差,如果是0,代表百分百精确计算。
cols = ["weight","height","age"]
# bounds,用来存储后面生成的各个字段值的边界
bounds = {}
for col in cols:
# 涉及统计中的4分位。计算Q1和Q3
quantiles = df_outliers.approxQuantile(col, [0.25,0.75], 0.05)
# 计算4分位距
IQR = quantiles[1] - quantiles[0]
# 计算内限
bounds[col] = [quantiles[0] - 1.5*IQR, quantiles[1] + 1.5*IQR]
print("bounds: ",bounds)
# 判断是否为异常值,在内限之外的值为异常值
outliers = df_outliers.select(*['id'] + \
[((df_outliers[c] < bounds[c][0]) | (df_outliers[c] > bounds[c][1]) )\
.alias(c +"_o") for c in cols])
outliers.show()
+---+--------+--------+-----+
| id|weight_o|height_o|age_o|
+---+--------+--------+-----+
| 1| false| false|false|
| 2| false| false|false|
| 3| true| false| true|
| 4| false| false|false|
| 5| false| false|false|
| 6| false| false|false|
| 7| false| false|false|
+---+--------+--------+-----+
# 再回头看看这些异常值的值,重新和原始数据关联
df_outliers = df_outliers.join(outliers, on='id')
df_outliers.filter('weight_o').select('id', 'weight').show()
+---+------+
| id|weight|
+---+------+
| 3| 342.3|
+---+------+
df_outliers.filter('age_o').select('id', 'age').show()
+---+---+
| id|age|
+---+---+
| 3| 99|
+---+---+
机器学习一般会将数据集划分为两个部分:
常见划分比例:
训练集 | 70% | 80% | 75% |
---|---|---|---|
测试集 | 30% | 20% | 25% |
sklearn
方法1:x_train, x_test, y_train, y_test = sklearn.model_selection.train_test_split(arrays, *options)
x
: 数据集的特征值y
: 数据集的标签值test_size
: 测试集的大小,在 [0, 1]之间,确定训练集和测试集比例random_state
: 随机数种子,不同的种子会造成不同的随机采样结果。相同的种子采样结果相同。方法2:df1,df2 = DataFlame.randomSplit([df1占比例, df2占比例],随机数种子)
例如 :trainDF, testDF = df.randomSplit([0.7, 0.3],100)
[2, 3] ==> [0.4, 0.6]
)spark
randomSplit
拆成两部分df1,df2 = DataFlame.randomSplit([df1占比例, df2占比例])
trainDF, testDF = df.randomSplit([0.6, 0.4])
sample
DataFlame.sample(抽样是否放回,采样比例,随机种子100)
sdf = df.sample(False,0.2,100)
抽样:从整体样本中通过一定的方法选择一部分样本
为什么要抽样
数据抽样的现实意义
如何进行抽样
抽样方法从整体上分为非概率抽样和概率抽样两种
非概率抽样:不是按照等概率的原则进行抽样,而是根据人类的主观经验和状态进行判断
可以解决样本不均衡(不同类别的样本量差异非常大)问题
样本分布不均衡将导致样本量少的分类所包含的特征过少,建立的模型容易过拟合。
如果不同分类间的样本量差异超过10倍就需要引起警觉,超过20倍就一定要想法解决了。
抽样:抽样是解决样本分布不均衡相对简单且常用的方法,包括过抽样和欠抽样两种。
SMOTE
算法。正负样本的惩罚权重:在算法实现过程中,对于分类中不同样本数量的类别分别赋予不同的权重(一般思路分类中的小样本量类别权重高,大样本量类别权重低),然后进行计算和建模。
scikit-learn
中的SVM
为例,通过在class_weight
:{dict,'balanced'}
中针对不同类别来手动指定权重,如果使用其默认的方法balanced
,那么SVM
会将权重设置为与不同类别样本数量呈反比的权重来进行自动均衡处理,计算公式如下:n_samples/(n_classes*np.bincount(y))
组合/集成:每次生成训练集时使用所有分类中的小样本量,同时从分类中的大样本量中随机抽取数据来与小样本量合并构成训练集,这样反复多次会得到很多训练集和训练模型。最后在应用时,使用组合方法(例如投票、加权投票等)产生分类预测结果。
100
条和10000
条,比例为1:100
。此时可以将负例样本(类别中的大量样本集)随机分为100
份(当然也可以分更多),每份100
条数据;然后每次形成训练集时使用所有的正样本(100
条)和随机抽取的负样本(100
条)形成新的数据集。如此反复可以得到100
个训练集和对应的训练模型。import pandas as pd
from imblearn.over_sampling import SMOTE # 过抽样处理库SMOTE
from imblearn.under_sampling import RandomUnderSampler # 欠抽样处理库RandomUnderSampler
# 使用SMOTE方法进行过采样处理
model_smote = SMOTE() # 建立SMOTE模型对象
x_smote_resampled, y_smote_resampled = model_smote.fit_sample(x, y) # 输入数据并作过采样处理
x_smote_resampled = pd.DataFrame(x_smote_resampled, columns=['col1', 'col2', 'col3', 'col4', 'col5']) # 将特征数据转换为 DataFrame 并命名列名
y_smote_resampled = pd.DataFrame(y_smote_resampled, columns=['label']) # 将目标数据转换为 DataFrame 并命名列名
smote_resampled = pd.concat([x_smote_resampled, y_smote_resampled], axis=1) # 按列合并DataFrame
# 使用RandomUnderSampler方法进行欠采样处理
model_RandomUnderSampler = RandomUnderSampler() # 建立RandomUnderSampler模型对象
x_RandomUnderSampler_resampled, y_RandomUnderSampler_resampled = model_RandomUnderSampler.fit_sample(x, y) # 输入数据并作欠采样处理
x_RandomUnderSampler_resampled = pd.DataFrame(x_RandomUnderSampler_resampled, columns=['col1', 'col2', 'col3', 'col4', 'col5']) # 将数据转换为数据框并命名列名
y_RandomUnderSampler_resampled = pd.DataFrame(y_RandomUnderSampler_resampled, columns=['label']) # 将数据转换为数据框并命名列名
RandomUnderSampler_resampled = pd.concat([x_RandomUnderSampler_resampled, y_RandomUnderSampler_resampled], axis=1) # 按列合并数据框
# 查看采样后的数据分布
groupby_data_RandomUnderSampler = RandomUnderSampler_resampled.groupby('label').count() # 对label做分类汇总
概率抽样:以数学概率论为基础,按照随机的原则进行抽样。
使用 Numpy 进行随机采样
shuffle_index = np.random.choice(np.arange(data.shape[0]),2000,True) # 随机生成2000个行号
data_sample = data[shuffle_index] # 从原始数据中取出2000个行号对应的数据
使用 Pandas 进行随机采样
DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)
参数:n :随机抽取的样本数(不能与frac一起使用)
frac:随机抽取的比例(不能与n一起使用)
replace:是否直接替换原DataFrom数据
weights:str或ndarray,可选
“None”:等概率加权
Series:将与索引上的目标对象对齐。在采样对象中找不到的权重索引值将被忽略,而在采样对象中没有权重的索引值将被分配为零。如果在DataFrame上调用,则在axis = 0时将接受列的名称。除非权重为Series,否则权重的长度必须与要采样的轴的长度相同。如果权重不等于1,则将它们归一化为总和1。权重列中的缺失值将被视为零。不允许使用无限值
random_state:随机种子
使用 Sklearn 采样数据
rdd1.sample(抽样是否放回,采样比例,随机种子)
# 等距抽样
data = np.loadtxt('data3.txt') # 导入普通数据文件
sample_count = 2000 # 指定抽样数量
record_count = data.shape[0] # 获取最大样本量
width = record_count / sample_count # 计算抽样间距
data_sample = [] # 初始化空白列表,用来存放抽样结果数据
i = 0 # 自增计数以得到对应索引值
while len(data_sample) <= sample_count and i * width <= record_count - 1: # 当样本量小于等于指定抽样数量并且矩阵索引在有效范围内时
data_sample.append(data[int(i * width)]) # 新增样本
i += 1 # 自增长
print(data_sample[:2]) # 打印输出前2条数据
print(len(data_sample)) # 打印输出样本数量
抽样需要注意的几个问题
作用:使用专业背景知识和技巧处理数据,使机器学习在关键的特征上学习并且简化计算量(其结果直接影响测试结果)
作用:将任意数据(如文本或图像)转换为可用于机器学习的数字特征
数据离散化
:在连续属性的值域上,将值域划分为若干个离散的区间,最后用不同的符号或整数值 代表落在每个子区间中的 属性值
one-hot编码
:把每个类别生成一个布尔列,这些列中只有一列可以为这个样本取值为1
其。又被称为热编码
分类特征转换为数值型索引
:对于一些分类比较多的特征并且值为字符串型数据,可以将特征分类转化成数值型索引
from sklearn.preprocessing import OrdinalEncoder
# 拆分数值特征和字符串特征
str_or_num = (df.dtypes=='object') # 返回值: 列名1 True/False 列名2 True/False ......
str_cols = str_or_num[str_or_num == True].index # 获取字符串特征列名
string_data = df[str_cols]
num_data = df[[i for i in str_or_num.index if i not in str_cols]]
# 分类特征转换为数值型索引
model_oe = OrdinalEncoder()
string_data_con = model_oe.fit_transform(string_data)
string_data_pd = pd.DataFrame(string_data_con,columns=string_data.columns)
# 合并原数值型特征和onehotencode后的特征
feature_merge = pd.concat((num_data,string_data_pd),axis=1)
代码实现
pandas 实现
数据离散化 data必须是一维数组 series
1. 等频离散化:离散结果series = pd.qcut(data, q) 每个区间样本数一致
2. 自定义区间离散:离散结果series = pd.cut(data, bins=自定义区间列表)
3. 使用聚类算法离散
统计每组的个数:离散结果series.value_counts():统计分组次数
one-hot 编码 主要在分类算法的数据处理 上应用
pandas.get_dummies(data, prefix=分组名字),只会对非数值类型的数据做转换
data 参数:可包含多列 可用数据类型 array-like、Series、DataFrame
sklearn
实现
连续数值的 二极化
from sklearn import preprocessing
# 此处是根据该列的平均数作为阈值,小于为0;大于为1
binarizer_scaler = preprocessing.Binarizer(threshold=df['income'].mean()) # 建立Binarizer模型对象
income_tmp = binarizer_scaler.fit_transform(df[['income']]) # Binarizer标准化转换
income_tmp.resize(df['income'].shape) # 转换数据形状
df['income'] = income_tmp # Binarizer标准化转换
将 list;np.array;pd.Series
一维数据进行one-hot 编码
from sklearn.preprocessing import LabelBinarizer # 导包
# 列表数据(list;np.array;pd.Series)不能是二维数组
data = ['动作片', '喜剧片', '爱情片', '科幻片']
data = np.array(data)
data = pd.Series(data)
transfer = LabelBinarizer()
data = transfer.fit_transform(data)
data = pd.DataFrame(data,columns=transfer.classes_)
print(data)
动作片 喜剧片 爱情片 科幻片
0 0 0 1 0
1 0 0 0 1
2 1 0 0 0
3 0 1 0 0
将字典数据进行one-hot 编码
(可以将pd.DataFrom.to_dict
转化成字典)
from sklearn.feature_extraction import DictVectorizer # 导包
# 字典数据
data = [{'city': '北京','temperature':100}, {'city': '上海','temperature':60}, {'city': '深圳','temperature':30}]
data = DataFrom 数组名.to_dict(orient="records")) # orient 表示转化成字典的样式
# 1、实例化一个转换器类 若 sparse=True 则表示生成稀疏矩阵, 对象.toarray() 将sparse矩阵转换为正常矩阵
transfer = DictVectorizer(sparse=False)
# 2、调用fit_transform
data = transfer.fit_transform(data)
# 打印转化后的 one-hot 编码矩阵
print("返回的结果:\n", data)
# 打印特征名字
print("特征名字:\n", transfer.get_feature_names())
返回的结果:
[[ 0. 1. 0. 100.]
[ 1. 0. 0. 60.]
[ 0. 0. 1. 30.]]
特征名字:
['city=上海', 'city=北京', 'city=深圳', 'temperature']
将 数组数据pd.DataFrame
进行one-hot 编码
from sklearn.preprocessing import OneHotEncoder # 导包
# 构造数据
data = [['有房',40,50000],
['无房',22,13000],
['有房',30,30000]]
data = pd.DataFrame(data,columns=['house','age','income'])
# 进行one-hot编码
enc = OneHotEncoder()
tempdata = enc.fit_transform(data).toarray()
# 获取特征名字
columns1 = enc.get_feature_names(['house','age','income'])
# 将 one-hot 矩阵 转换成 DataFrom
tempdata = pd.DataFrame(tempdata,columns=list(columns1))
spark
实现(三步才能实现)
StringIndexer
:对指定字符串列数据进行特征处理(将其转化成:1、2、3、4 … )OneHotEncoder
:对特征列数据进行热编码(常需结合StringIndexer
使用)Pipeline
:让数据按顺序依次处理,将前一次的处理结果作为下一次的输入from pyspark.ml.feature import OneHotEncoder StringIndexer
from pyspark.ml import Pipeline
# StringIndexer对指定字符串列进行特征处理
stringindexer = StringIndexer(inputCol='pid', outputCol='pid_feature')
# 对处理出来的特征处理列进行,one-hot 编码
encoder = OneHotEncoder(dropLast=False, inputCol='pid_feature', outputCol='pid_value')
# 创建管道并设定处理顺序,上一个处理的结果作为下一个的处理的输入
pipeline = Pipeline(stages=[stringindexer, encoder])
# 利用管道训练数据集
pipeline_model = pipeline.fit(raw_sample_df)
new_df = pipeline_model.transform(raw_sample_df)
new_df.show() # 处理完的数据集会新增 pid_feature 和 pid_value 两列,其中pid_value为稀疏矩阵,可用 .toArray() 转化为正常矩阵显示
sklearn
import jieba # 导入 jieba 分词
import collections # 词频统计库
string_data = "我爱北京,北京"
seg_list_exact = jieba.cut(string_data, cut_all=False) # jieba.cut() 将中文进行精确模式分词
# Counter({'我': 1, '爱': 1, '北京': 2, ',': 1})
word_counts = collections.Counter(seg_list_exact ) # 对分词做词频统计
# [('北京', 2), ('我', 1), ('爱', 1), (',', 1)]
word_counts_top5 = word_counts.most_common(5) # 获取前10个频率最高的词
# 可以获取分词 词性
import jieba.posseg as pseg
words = pseg.cut(string_data) # 分词,返回值为慈和词性,不会对词进行统计
words_pd = pd.DataFrame(words, columns=['词', '词性']) # 创建结果数据框
# 词性分类汇总-两列分类
words_gb = words_pd.groupby(['词性', '词'])['词'].count()
# 词性 词
# ns 北京 2
# r 我 1
# v 爱 1
# x , 1
# 选择特定类型词语做展示
words_pd_index = words_pd['词性'].isin(['ns', 'eng'])
# 关键字提取
import jieba.analyse # 导入关键字提取库
tags_pairs = jieba.analyse.extract_tags(string_data, topK=5, withWeight=True, allowPOS=['ns', 'n', 'vn', 'v', 'nr'], withFlag=True) # 提取关键字标签
tags_list = [(i[0].word, i[0].flag, i[1]) for i in tags_pairs] #
tags_pd = pd.DataFrame(tags_list, columns=['word', 'flag', 'weight']) # 创建数据框
# word flag weight
# 0 北京 ns 4.667402
# 文本提取API:
sklearn.feature_extraction.text.CountVectorizer(stop_words=['停用词列表'])
训练数据:CountVectorizer.fit_transform(X) # 参数X:文本或者包含文本字符串的可迭代对象
返回值:返回 one-hot 的 sparse矩阵
注意没有sparse参数
对象.toarray() 将sparse矩阵转换为正常矩阵
[1, 0, 0]
[0, 1, 0]
[0, 0, 2]
属性:CountVectorizer.get_feature_names() :单词列表
['我', '爱', '北京']
主要思想:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF-IDF
作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度
公式:
tf
词频:某一个给定的词语在该文件中出现的频率idf
逆向文档频率:一个词语普遍重要性的度量。某一特定词语的idf
,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10
为底的对数得到sklearn
sklearn.feature_extraction.text.TfidfVectorizer()
# 1、实例化转换器类
transfer = TfidfVectorizer(stop_words=['停用词(不用于统计的无意义的词)'])
# 2、调用fit_transform
data = transfer.fit_transform(text_list) # 若text_list中包含 中文,则需要使用jieba.cut()进行分词
print("文本特征抽取的结果:\n", data.toarray()) # 默认输出 one-hot 的系数矩阵
print("返回特征名字:\n", transfer.get_feature_names())
作用:通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程
意义:将特征值无量纲化,即将所有的特征值映射到同一范围(一般为0-1之间)内,使不同规格的数据转换到同一规格。避免因 特征的 单位、大小 或 方差 相差几个数量级,从而 影响或支配学习结果,使得算法无法学习到其它的特征
归一化作用:通过对原始数据进行变换把数据映射到(默认为[0,1]
)之间,将不同特征数据无量纲化,使不同规格的数据转换到同一规格
max
为一列的最大值min
为一列的最小值mx
和mi
分别为指定区间的上限和下限,默认:mx
为1,mi
为0对象名 = sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
feature_range
表示将数据处理到的指定区间,默认(0,1)
对象名.fit_transform(X)
X
:需要归一化的数据集(numpy array
格式数据)data['milage','Liters','Consumtime']
array
数据集归一化的缺陷:因为最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景
归一化进阶版:标准化
规避掉了异常值的影响,适合现代嘈杂大数据场景
注意:标准化是一种中心化方法,会改变原有数据的分布结构,不适合对稀疏数据做处理
mean
为平均值,σ
为标准差
sklearn
代码实现:
对象名 = sklearn.preprocessing.StandardScaler ()
对象名.fit_transform(X)
X
:需要归一化的数据集(numpy array
格式数据)data['milage','Liters','Consumtime']
array
数据集数据标准化后存在的方法:
对象名.mean_
:获取每一列特征的平均值
对象名.var_
:获取每一列特征的方差
spark
代码实现:
对象名 = pyspark.ml.feature.StandardScaler()
withMean = False
:withStd = True
:inputCol = None
:outputCol = None
:pd.DataFrame(df.groupby('uid').apply(lambda df:len(df[i])).reset_index())
pd.DataFrame(df.groupby('uid').apply(lambda df:np.where(df[i]>0,1,0).sum()).reset_index())
pd.DataFrame(df.groupby('uid').apply(lambda df:np.nansum(df[i])).reset_index())
nanmean
;统计最大值:nanmax
;最小值:nanmin
;统计方差:nanvar
;统计极差:nanmax-nanmin
原因:在训练模型时,是使用特征进行学习。如果特征本身存在问题或者特征之间相关性较强,对于算法学习预测会影响较大
作用:在不损失或少量损失信息实现 特征个数(维度)减少的过程
指在某些限定条件下,降低随机变量(特征)个数,得到一组“不相关”主变量的过程
数据中包含冗余或无关变量(或称特征、属性、指标等),旨在从原有特征中找出主要特征。
Filter
(过滤式):主要探究特征本身特点、特征与特征和目标值之间关联
Embedded
(嵌入式):算法自动选择特征(特征与目标值之间的关联)
删除 低方差 的一些特征
特征方差小:某个特征大多样本的值比较相近
特征方差大:某个特征很多样本的值都有差别
sklearn
实现:
sklearn.feature_selection.VarianceThreshold(threshold = 0.0)
初始化VarianceThreshold
,指定阀值方差
Variance.fit_transform(X)
调用fit_transform
参数X
:数据集(numpy array格式
)[n_samples,n_features]
返回值:训练集差异低于threshold
的特征将被删除。threshold
默认值为0,即删除所有样本中具有相同值的特征。
反映变量之间相关关系密切程度的统计指标
相关系数的值介于 –1 与 +1 之间,其性质如下:
r>0
时,表示两变量正相关,r<0
时,两变量为负相关|r|=1
时,表示两变量为完全相关r=0
时,表示两变量间无相关关系0<|r|<1
时,表示两变量存在一定程度的相关。|r|
越接近1
,两变量间线性关系越密切一般可按三级划分:
|r|<0.4
为低度相关0.4≤|r|<0.7
为显著性相关0.7≤|r|<1
为高度线性相关Pandas API
:
df.corr() # 获取各个特征之间的相关系数
# 获取最相关的特征排序
df.corr([['目标值']].sort_values('目标值',ascending=False)
scipy API
:
from scipy.stats import pearsonr
pearsonr(x, y)
参数:
x : (N,) 第一特征列数据
y : (N,) 第二特征类数据
返回值: (两个特征之间的皮尔逊相关系数,p-value)
反映变量之间相关关系密切程度的统计指标
斯皮尔曼相关系数表明 X (自变量) 和 Y (因变量)的相关方向
如果当X增加时, Y 趋向于增加, 斯皮尔曼相关系数则为正
与之前的皮尔逊相关系数大小性质一样,取值 [-1, 1]之间
斯皮尔曼相关系数比皮尔逊相关系数应用更加广泛
scipy API
:
from scipy.stats import spearmanr
x1 = [12.5, 15.3, 23.2, 26.4, 33.5, 34.4, 39.4, 45.2, 55.4, 60.9] # 第一特征列数据
x2 = [21.2, 23.9, 32.9, 34.1, 42.5, 43.2, 49.0, 52.8, 59.4, 63.5] # 第二特征列数据
spearmanr(x1, x2)
结果
SpearmanrResult(correlation=0.9999999999999999, pvalue=6.646897422032013e-64)
根据逻辑回归或XGBoost获取的特征权重,获取最重要的几个特征
通过L1正则项,将不重要的特征权重置于0,可以通过 feature_selection.SelectFromModel
来选择权重不为0的特征
svm.LinearSVC()
from sklearn.feature_selection import SelectFromModel
from sklearn.svm import LinearSVC
lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X,y)
model = SelectFromModel(lsvc, prefit=True)
X_embed = model.transform(X)
X_embed.shape
linear_model.Lasso()
linear_model.LogisticRegression()
lightgbm
和XGBoost
一样,都是 Boosting
集成思想 +
二阶泰勒展开 +
决策树模型 +
正则项
import lightgbm as lgb
def lgb_test(train_x,train_y,test_x,test_y):
clf =lgb.LGBMClassifier(boosting_type = 'gbdt',
objective = 'binary',
metric = 'auc',
learning_rate = 0.1,
n_estimators = 24,
max_depth = 5,
num_leaves = 20,
max_bin = 45,
min_data_in_leaf = 6,
bagging_fraction = 0.6,
bagging_freq = 0,
feature_fraction = 0.8,
)
clf.fit(train_x,train_y,eval_set = [(train_x,train_y),(test_x,test_y)],eval_metric = 'auc')
return clf,clf.best_score_['valid_1']['auc'],
lgb_model , lgb_auc = lgb_test(train_x,train_y,test_x,test_y)
feature_importance = pd.DataFrame({'name':lgb_model.booster_.feature_name(),
'importance':lgb_model.feature_importances_})
.sort_values(by=['importance'],ascending=False)
import xgboost as xgb
xgb_model = xgb.XGBClassifier().fit(X,y)
feature_importances = xgb_model.feature_importances_
indices = np.argsort(feature_importances)[::-1]
for index in indices:
print("特征 %s 重要度为 %f" %(feature_names[index], feature_importances[index]))
定义:高维数据转化为低维数据的过程,在此过程中可能会舍弃原有数据、创造新的变量
作用:是数据维数压缩,尽可能降低原数据的维数(复杂度),损失少量信息。
sklearn API
:
sklearn.decomposition.PCA(n_components=None) # 将数据分解为较低维数空间
参数:
n_components:
小数:表示保留百分之多少的信息
整数:减少到多少特征
PCA.fit_transform(X)
参数:
X:整个特征数据,numpy array格式的数据 [n_samples,n_features]
返回值:转换后指定维度的array
estimator = 算法API函数
estimator.fit(训练集的特征值, 测试集的特征值)
,early_stopping_rounds=10, eval_metric="auc", eval_set=[(X_val, y_val)
estimator.predict(测试数据的特征值)
预测结果经典算法 及 其API(另一篇博客)
监督学习
输入数据是由输入特征值和目标值所组成,其有分为回归于分类两种
回归(目标值为连续型,函数的输出可以是一个连续的值)
线性回归(岭回归):根据自变量(特征)和因变量(目标值)之间的关系 进行建模
分类(目标值为离散型,或是输出是有限个离散值)
通过对已知类别训练集的计算和分析,从中发现类别规则并预测新数据的类别
无监督学习(仅有特征值而没有目标值)
聚类:将大量数据集中具有“相似”特征的数据点或样本划分为同一类别(根据不同的特征聚类,产生的聚类结果不同)
RFM
)等数据半监督学习
训练集同时包含有标记样本数据和未标记样本数据
make decisions
问题,即自动进行决策,并且可以做连续决策。agent
, action
,reward
, environment
, observation
;agent
,他试图通过采取行动(即行走)来操纵环境(行走的表面),并且从一个状态转变到另一个状态(即他走的每一步),当他完成任务的子任务(即走了几步)时,孩子得到奖励(给巧克力吃),并且当他不能走路时,就不会给巧克力。算法分类 | 输入的数据 | 输出 | 目的 | 案例 |
---|---|---|---|---|
监督学习 (supervised learning ) |
有标签 | 有反馈 | 预测结果 | 猫狗分类 房价预测 |
无监督学习 (unsupervised learning ) |
无标签 | 无反馈 | 发现潜在结构 | “物以类聚,人以群分” |
半监督学习 (Semi-Supervised Learning ) |
部分有标签,部分无标签 | 有反馈 | 降低数据标记的难度 | |
强化学习 (reinforcement learning ) |
决策流程及激励系统 | 一系列行动 | 长期利益最大化 | 学下棋 |
作用:于发现表达数据的最佳模型和所选模型将来工作的性能如何。
评估方式:二元分类使用AUC
.多元分类使用accuracy
、回归分析使用RMSE
模型评估用于评价训练好的的模型的表现效果,其表现效果大致可以分为两类:过拟合、欠拟合。
欠拟合(under-fitting
):模型学习的太过粗糙(在训练数集和测试集上皆没有很好的拟合数据),没有学习到数据的特征,在训练集和测试集评估效果均不好
欠拟合原因以及解决办法
过拟合(over-fitting
):模型过于复杂(模型尝试去兼顾各个测试数据点),设置特征过多,所建的模型过于拟合训练样本数据,导致在测试数据集中表现不佳
过拟合原因以及解决办法
混淆矩阵:在分类任务下,预测结果(Predicted Condition
)与正确标记(True Condition
)之间存在四种不同的组合,构成混淆矩阵(适用于多分类)
准确率:预测正确的数占样本总数的比例((TP+TN)/(TP+TN+FN+FP)
)表示预测的对不对
sklearn API
:模型.score(x_test, y_test)
用于:不关注预测的准确率,而是关注在所有的样本当中 某分类(确诊癌症) 有没有被全部预测出来
精确率:预测结果为正例样本中真实为正例的比例(TP/(TP+FP)
)表示预测的准不准
召回率:真实为正例的样本中预测结果为正例的比例(TP/(TP+FN)
)标是查的全不全
F1-score
,反映了模型的稳健性
sklearn
分类评估报告API:sklearn.metrics.classification_report(y_true, y_pred, labels=[], target_names=None )
参数:
y_true
:真实目标值y_pred
:估计器预测的目标值labels
:指定目标值类别对应的数字target_names
:为目标值类别起别名用于人性化现实返回值:每个类别的 精确率、召回率、F1-score
混淆矩阵API
:sklearn.metrics.confusion_matrix(y_true, y_pred)
作用:适合样本不均衡情况,比较哪个模型更好
ROC曲线
横坐标:FPR = FP / (FP + TN)
所有真实类别为0的样本中,预测类别为1的比例
纵坐标:TPR = TP / (TP + FN)
所有真实类别为1的样本中,预测类别为1的比例
(0,0)
表示:全预测为假(1,1)
表示:前预测为真AUC指标 和 KS值
计算ROC
线下面积,即AUC
值
AUC
的概率意义是随机取一对正负样本,正样本得分大于负样本得分的概率AUC
的范围在[0, 1]
之间,并且越接近1越好,越接近0.5属于乱猜AUC=1
:完美分类器,绝大多数预测的场合,不存在完美分类器。0.5:优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值
TPR - FPR
的最大值,即KS
值(主要用于风控模型)
0.4>KS>0.2
勉强可用0.6>KS>0.4
一般KS > 0.7
较好AUC计算API
sklearn
导入模块:from sklearn.metrics import roc_auc_score
计算API:roc_auc_score(y_true, y_score)
y_true
:每个样本的真实类别,必须为0(反例),1(正例)标记y_score
:预测得分,可以是正类的估计概率、置信值 或者 分类器方法的预测值(y_pred
)# 方法二
from sklearn.metrics import roc_curve,auc
fpr,tpr,threshold=roc_curve(y_train,y_pred_train)
roc_auc=auc(fpr,tpr)
roc_ks=abs(fpr-tpr).max()
AUC只能用来评价二分类,非常适合评价样本不平衡中的分类器性能
MSE
是一个衡量回归模型误差率的常用公式。 不过,它仅能比较误差是相同单位的模型。
代码实现:
Pandas 直接计算
:
predictions=model模型.predict(x) # 根据模型获取y预测值
error=predictions-y # 计算误差
mse=(error**2).mean() # 计算 mse
rse=(error**2).mean()**.5 # 计算 rse
mae=abs(error).mean() # 计算 mae
sklearn API
:sklearn.metrics.mean_squared_error(y_true, y_pred)
y_true
:真实值y_pred
:预测值return
返回值:浮点数均方根结果其他评价指标:
Relative Squared Error
,RSE
)mean_absolute_error
,MAE
)Relative Absolute Error
,RAE
)R2
:目标的变化由特征引起的比例
只要R2
达到0.5-0.6
就已经很好了
此外,从理论上来说,只要增加特征的个数,R2
的值是一直增加的,不管这个特征x和目标y是否有关。
因此,R2
通常用于特征选择。如果增加一个特征,模型的R2
值上升很多,那就说明这个特征和目标有关。
adjusted R2
:与R2
类似,不过增加了惩罚项,因此adjusted R2
一定小于等于R2
。
如果新增的特征没有带来任何有用的信息,那么adjusted R2
会变小,只有在新增的特征带来足够多的信息(足够抵消惩罚项)时,adjusted R2
才会增加。其缺点是无法像R2
一样对模型进行解释
如果以R2
为评价指标,容易让模型出现过拟合现象,因此建议用adjusted R-squared
来选择模型,用R2
来解释模型
sklearn
from sklearn.externals import joblib
joblib.dump(训练好的模型, '路径/模型名.pkl')
estimator = joblib.load('路径/模型名.pkl')
需要变量承接