《Spark机器学习》笔记——Spark回归模型(最小二乘回归、决策树回归,模型性能评估、目标变量变换、参数调优)

数据集说明:

数据集下载地址

http://archive.ics.uci.edu/ml/machine-learning-databases/00275/Bike-Sharing-Dataset.zip

=========================================
hour.csv和day.csv都有如下属性,除了hour.csv文件中没有hr属性以外

- instant: 记录ID
- dteday : 时间日期
- season : 季节 (1:春季, 2:夏季, 3:秋季, 4:冬季)
- yr : 年份 (0: 2011, 1:2012)
- mnth : 月份 ( 1 to 12)
- hr : 当天时刻 (0 to 23)
- holiday : 当天是否是节假日(extracted from http://dchr.dc.gov/page/holiday-schedule)
- weekday : 周几
- workingday : 工作日 is 1, 其他 is 0.
+ weathersit : 天气
- 1: Clear, Few clouds, Partly cloudy, Partly cloudy
- 2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist
- 3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds
- 4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog
- temp : 气温 Normalized temperature in Celsius. The values are divided to 41 (max)
- atemp: 体感温度 Normalized feeling temperature in Celsius. The values are divided to 50 (max)
- hum: 湿度 Normalized humidity. The values are divided to 100 (max)
- windspeed: 风速Normalized wind speed. The values are divided to 67 (max)
- casual: 临时用户数count of casual users
- registered: 注册用户数count of registered users
- cnt: 目标变量,每小时的自行车的租用量,包括临时用户和注册用户count of total rental bikes including both casual and registered

=========================================

使用sed 1d hour.csv > hour_noheader.csv去掉第一行

使用jupyter notebook进入开发环境





代码:

from pyspark import SparkContext#导入Spark的Python库
sc = SparkContext("local","bike")#本地运行。

path = "file:///home/chenjie/bike/hour_noheader.csv"#已将数据集放在此路径下,并已去掉第一行的头信息
raw_data = sc.textFile(path)#加载数据
records = raw_data.map(lambda x: x.split(","))#用,隔开,获得记录
num_data = raw_data.count()#得到总记录数
first = records.first()#得到第一行
print first#打印第一行
print num_data#打印总总记录数

def get_mapping(rdd, idx):
    return rdd.map(lambda fields: fields[idx]).distinct().zipWithIndex().collectAsMap()
#以上定义了一个映射函数:首先将第idx列的特征值去重,然后对每个值使用zipWithIndex函数映射到一个唯一的索引,这样就组成了一个RDD的键值映射
#键是变量,值是索引

print records.map(lambda fields: fields[2]).distinct().collect()
#输出结果为[u'1', u'3', u'2', u'4']
#表明第三列(季节)只有1,3,2,4四种取值

print "Mapping of first categorical feasture column: %s" % get_mapping(records, 2)
#Mapping of first categorical feasture column: {u'1': 0, u'3': 1, u'2': 2, u'4': 3}
#将1,3,2,4映射到0,1,2,3

mappings = [get_mapping (records, i) for i in range(2,10) ]#将记录中的每一列都这样映射
cat_len = sum(map(len, mappings))#类型变量的长度
num_len = len(records.first()[11:15])#实数变量的长度
total_len = num_len + cat_len#总长度
print "Feature vector length for categorical features : %d" % cat_len
print "Feature vector length for numerical features : %d" % num_len
print "Total feature vector length : %d" % total_len

#1、为线性模型创建特征向量
from pyspark.mllib.regression import LabeledPoint
import numpy as np

#以下函数为线性模型创建特征向量
def extract_features(record):
    cat_vec = np.zeros(cat_len)#先新建一个cat_len长度的0向量
    i = 0
    step = 0
    for field in record[2 : 9]:
        m = mappings[i]#某属性的特征map
        idx = m[field]#得到下标
        cat_vec[idx + step] = 1 #将cat_vec向量的对应位置置为1
        i = i + 1
        step = step + len(m)#步数往后走
    num_vec = np.array([float(field) for field in record[10 : 14]])#取出实数属性组成实数向量
    return np.concatenate((cat_vec, num_vec))#将类别向量和实数向量合并

def extract_label(record):
    return float(record[-1])

data = records.map(lambda r : LabeledPoint(extract_label(r), extract_features(r)))
first_point = data.first()
print "Raw data :" + str(first[2:]) 
print "Label:" + str(first_point.label)
print "Linear Model feature vector:\n" + str(first_point.features)
print "Linear Model feature vector length :" + str(len(first_point.features))

#以下部分代码创建决策树的特征向量
def extract_features_dt(record):
    return np.array(map(float, record[2 : 14]))

data_dt = records.map(lambda r : LabeledPoint(extract_label(r), extract_features_dt(r)))
first_point_dt = data_dt.first()
print "Decision Tree feature vector: " + str(first_point_dt.features)
print "Decision Tree feature vector length :" + str(len(first_point_dt.features))


#以下部分使用线性回归训练模型
from pyspark.mllib.regression import LinearRegressionWithSGD
from pyspark.mllib.tree import DecisionTree
linear_model = LinearRegressionWithSGD.train(data, iterations = 10, step = 0.1, intercept = False)
true_vs_predicted = data.map(lambda p : (p.label, linear_model.predict(p.features)))
print "Linear Model predictions " + str(true_vs_predicted.take(5))

#以下部分使用决策树训练模型
dt_model = DecisionTree.trainRegressor(data_dt, {})
preds = dt_model.predict(data_dt.map(lambda p : p.features))
actual = data.map(lambda p : p.label)
true_vs_predicted_dt = actual.zip(preds)
print "Decision Tree predictions :" + str(true_vs_predicted_dt.take(5))
print "Decision Tree depth :" + str(dt_model.depth())
print "Decision Tree number of nodes :" + str(dt_model.numNodes())

#均方误差
def squared_error(actual, pred):
    return (pred - actual) ** 2

#平均绝对误差
def abs_error(actual, pred):
    return np.abs(pred - actual)

#均方根对数误差
def squared_log_error(actual, pred):
    return (np.log(pred + 1) - np.log(actual + 1)) ** 2

#以下部分得到线性回归的三个指标
mse = true_vs_predicted.map(lambda (t, p): squared_error(t, p)).mean()
print "Linear Model - Mean Squared Error : %2.4f" % mse

mae = true_vs_predicted.map(lambda (t, p): abs_error(t, p)).mean()
print "Linear Model - Mean Absolute Error: %2.4f" % mae

rmsle = np.sqrt(true_vs_predicted.map(lambda (t, p): squared_log_error(t, p)).mean())
print "Linear Model - Root Mean Squared Log Error: %2.4f" % rmsle


#以下部分得到决策树的三个指标
mse_dt = true_vs_predicted_dt.map(lambda (t, p) : squared_error(t, p)).mean()
print "Decision Tree - Mean Squared Error : %2.4f" % mse_dt

mae_dt = true_vs_predicted_dt.map(lambda (t, p) : abs_error(t, p)).mean()
print "Decision Tree - Mean Absolute Error: %2.4f" % mae_dt

rmsle_dt = np.sqrt(true_vs_predicted_dt.map(lambda (t, p): squared_log_error(t, p)).mean())
print "Linear Model - Root Mean Squared Log Error: %2.4f" % rmsle_dt

#观察目标变量
targets = records.map(lambda r : float(r[-1])).collect()
from matplotlib import pyplot as plt
plt.hist(targets, bins=40, color='green', normed=True)
fig = plt.gcf()
fig.set_size_inches(16,10)
plt.show()

#变幻目标变量——取对数
log_targets = records.map(lambda r : np.log(float(r[-1]))).collect()
plt.hist(log_targets, bins=40, color='green', normed=True)
fig = plt.gcf()
fig.set_size_inches(16,10)
plt.show()

#开方
sqrt_targets = records.map(lambda r : np.sqrt(float(r[-1]))).collect()
plt.hist(sqrt_targets, bins=40, color='green', normed=True)
fig = plt.gcf()
fig.set_size_inches(16,10)
plt.show()

data_log = data.map(lambda lp : LabeledPoint(np.log(lp.label), lp.features))
model_log = LinearRegressionWithSGD.train(data_log, iterations=10, step=0.1)
true_vs_predicted_log = data_log.map(lambda p : (np.exp(p.label), np.exp(model_log.predict(p.features))))

mse_log = true_vs_predicted_log.map(lambda (t, p): squared_error(t, p)).mean()
print "Linear Model - Mean Squared Error : %2.4f" % mse_log

mae_log = true_vs_predicted_log.map(lambda (t, p): abs_error(t, p)).mean()
print "Linear Model - Mean Absolute Error: %2.4f" % mae_log

rmsle_log = np.sqrt(true_vs_predicted.map(lambda (t, p): squared_log_error(t, p)).mean())
print "Linear Model - Root Mean Squared Log Error: %2.4f" % rmsle_log

print "未对原数据进行对数操作时:\n" + str(true_vs_predicted.take(3)) 
print "对原数据进行对数操作时:\n" + str(true_vs_predicted_log.take(3)) 


data_dt_log = data_dt.map(lambda lp : LabeledPoint(np.log(lp.label), lp.features))
dt_model_log = DecisionTree.trainRegressor(data_dt_log, {})
preds_log = dt_model_log.predict(data_dt_log.map(lambda p : p.features))
actual_log = data_dt_log.map(lambda p: p.label)
true_vs_predicted_dt_log = actual_log.zip(preds_log).map(lambda (t, p) : (np.exp(t), np.exp(p)))

mse_log_dt = true_vs_predicted_dt_log.map(lambda (t, p): squared_error(t, p)).mean()
print "Decision Tree - Mean Squared Error : %2.4f" % mse_log_dt

mae_log_dt = true_vs_predicted_dt_log.map(lambda (t, p): abs_error(t, p)).mean()
print "Decision Tree - Mean Absolute Error: %2.4f" % mae_log_dt

rmsle_log_dt = np.sqrt(true_vs_predicted_dt_log.map(lambda (t, p): squared_log_error(t, p)).mean())
print "Decision Tree - Root Mean Squared Log Error: %2.4f" % rmsle_log_dt

print "未对原数据进行对数操作时:\n" + str(true_vs_predicted_dt.take(3)) 
print "对原数据进行对数操作时:\n" + str(true_vs_predicted_dt_log.take(3)) 


data_with_idx = data.zipWithIndex().map(lambda (k, v) : (v, k))
test = data_with_idx.sample(False, 0.2, 42)
train = data_with_idx.subtractByKey(test)

train_data = train.map(lambda (idx, p) : p)
test_data = test.map(lambda (idx, p) : p)
train_size = train_data.count()
test_size = test_data.count()
print "训练集大小:%d" % train_size
print "测试集大小:%d" % test_size
print "总共大小:%d" % num_data
print "训练集大小 + 测试集大小:%d" %  (train_size + test_size)


data_with_idx_dt = data_dt.zipWithIndex().map(lambda (k, v) : (v, k))
test_dt = data_with_idx_dt.sample(False, 0.2, 42)
train_dt = data_with_idx_dt.subtractByKey(test_dt)
train_data_dt = train_dt.map(lambda (idx, p) : p)
test_data_dt = test_dt.map(lambda (idx, p) : p)
train_size_dt = train_data_dt.count()
test_size_dt = test_data_dt.count()
print "训练集大小:%d" % train_size_dt
print "测试集大小:%d" % test_size_dt
print "总共大小:%d" % num_data
print "训练集大小 + 测试集大小:%d" %  (train_size_dt + test_size_dt)

def evaluate(train, test, iterations, step, regParam, regType, intercept):
    model= LinearRegressionWithSGD.train(train, iterations, step, regParam=regParam, regType=regType, intercept=intercept)
    tp = test.map(lambda p : (p.label, model.predict(p.features)))
    rmsle = np.sqrt(tp.map(lambda (t, p) : squared_log_error(t, p)).mean())
    return rmsle
#迭代次数对性能的影响
params = [1, 5, 10, 20, 50, 100]
metrics = [evaluate(train_data, test_data, param, 0.01, 0.0, 'l2', False) for param in params]
#注意这里是字母L的小写l不是1
print params
print metrics
plt.plot(params, metrics)
fig = plt.gcf()
plt.xlabel("iterations")
plt.ylabel("RMSLE")
plt.show()


params = [0.01, 0.025, 0.05, 0.1, 1.0]
metrics = [evaluate(train_data, test_data, 10,param, 0.0, 'l2', False) for param in params]
#注意这里是字母L的小写l不是1
#步长对性能的影响
print params
print metrics
plt.plot(params, metrics)
fig = plt.gcf()
plt.xlabel("step")
plt.ylabel("RMSLE")
plt.show()


params = [0.1, 0.01, 0.1, 1.0, 5.0, 10.0, 20.0]
metrics = [evaluate(train_data, test_data, 10, 0.1, param, 'l2', False) for param in params]
#注意这里是字母L的小写l不是1
#正则化参数对性能的影响
print params
print metrics
plt.plot(params, metrics)
fig = plt.gcf()
plt.xlabel("regParam")
plt.xscale('log')
plt.ylabel("RMSLE")
plt.show()

params = [0.1, 0.01, 0.1, 1, 10.0, 100.0, 1000.0]
metrics = [evaluate(train_data, test_data, 10, 0.1, param, 'l1', False) for param in params]
#注意这里是字母L的小写l不是1
print params
print metrics
plt.plot(params, metrics)
fig = plt.gcf()
plt.xlabel("regParam")
plt.xscale('log')
plt.ylabel("RMSLE")
plt.title("when regType change to l1 from l2")
plt.show()


model_l1 = LinearRegressionWithSGD.train(train_data, 10, 0.1, regParam=1.0, regType='l1', intercept=False)
model_l1_10 = LinearRegressionWithSGD.train(train_data, 10, 0.1, regParam=10.0, regType='l1', intercept=False)
model_l1_100 = LinearRegressionWithSGD.train(train_data, 10, 0.1, regParam=100.0, regType='l1', intercept=False)
print "L1(1.0)权重向量中0个书目:" + str(sum(model_l1.weights.array == 0))
print "L1(10.0)权重向量中0个书目:" + str(sum(model_l1_10.weights.array == 0))
print "L1(100.0)权重向量中0个书目:" + str(sum(model_l1_100.weights.array == 0))


params = [False, True]
metrics = [evaluate(train_data, test_data, 10, 0.1, 1.0, 'l2', param) for param in params]
#注意这里是字母L的小写l不是1
print params
print metrics
plt.bar(params, metrics)
fig = plt.gcf()
plt.xlabel("intercept")
plt.ylabel("RMSLE")
plt.show()


def evaluate_dt(train, test, maxDepth, maxBins):
    model = DecisionTree.trainRegressor(train, {}, impurity='variance', maxDepth=maxDepth, maxBins=maxBins)
   # print model 
    preds = model.predict(test.map(lambda p : p.features))
    actual = test.map(lambda p : p.label)
    tp = actual.zip(preds)
    rmsle = np.sqrt(tp.map(lambda (t, p) : squared_log_error(t, p)).mean())
    return rmsle
    
params = [1, 2, 3, 4, 5, 10, 20]
metrics = [evaluate_dt(train_data_dt, test_data_dt, param, 32) for param in params]
print params
print metrics
plt.plot(params, metrics)
fig = plt.gcf()
plt.title("maxDepth's influence on DecisionTree")
plt.xlabel("maxDepth")
plt.ylabel("RMSLE")
plt.show()

params = [2, 4, 8, 16, 32, 64, 100]
metrics = [evaluate_dt(train_data_dt, test_data_dt, 5, param) for param in params]
print params
print metrics
plt.plot(params, metrics)
fig = plt.gcf()
plt.title("maxBins's influence on DecisionTree")
plt.xlabel("maxBins")
plt.ylabel("RMSLE")
plt.show()





  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Spark性能优化指南的基础篇主要包括开发调优和资源调优两个方面,其中设置参数是资源调优的重要内容。 在开发调优方面,需要注意以下几点: 1. 避免使用不必要的shuffle操作,因为shuffle操作会导致数据的重新分区和网络传输,从而影响性能。 2. 尽量使用RDD的转换操作,而不是行动操作,因为行动操作会触发计算并返回结果,而转换操作只是定义了计算过程,不会立即执行。 3. 使用广播变量来减少数据的传输,广播变量可以将一个只读变量缓存到每个节点上,避免重复传输。 在资源调优方面,需要注意以下几点: 1. 设置合适的内存分配比例,可以通过调整spark.driver.memory和spark.executor.memory参数来实现。 2. 设置合适的并行度,可以通过调整spark.default.parallelism参数来实现。 3. 设置合适的序列化方式,可以通过调整spark.serializer和spark.kryoserializer.buffer.max参数来实现。 4. 设置合适的存储级别,可以通过调整RDD的存储级别来实现。 总之,通过合理设置参数和优化代码,可以提高Spark性能和效率。 ### 回答2: Spark性能优化是一个非常复杂的过程,它通常被视为一项高级技能。在Spark的使用过程中,开发调优和资源调优都是非常重要的,这篇文章将重点介绍一些基础篇的内容,包括开发调优和资源调优中的设置参数。 首先,我们来看一下开发调优。在Spark中,开发者需要注意一些代码实践,以确保代码的性能最优。以下是一些开发调优的最佳实践: 1.避免使用lambda表达式,特别是在数据集或数据框的操作中。虽然lambda表达式在编码过程中非常方便,但它们往往会导致不必要的对象和内存分配,从而降低了性能。 2.尽可能地使用原语而不是高级API。原语比高级API实现更快,同时也具有更多的控制力。例如,使用RDD代替DataFrame可能会带来更好的性能。 3.使用宽依赖(例如reduceByKey)代替窄依赖(例如groupByKey)。宽依赖通过并行化来提高执行效率,而窄依赖则依赖于串行执行。 4.尽可能的避免使用全局变量或静态变量,因为它们会使Spark的并行性降低并导致性能下降。 接下来,我们将讨论资源调优中设置参数的相关内容。在Spark的资源调优中,设置参数是非常重要的,因为它们可以帮助我们优化内存、CPU、网络等资源的使用,从而实现更好的性能。 1.调整executor内存大小。这是最基本的调优步骤,executor内存越大,Spark可以处理的数据量就越大,从而带来更好的性能。通常,设置executor内存为节点可用内存大小的三分之一是比较合理的。 2.调整shuffle分区数。调整shuffle分区数对于网络和I/O使用非常重要。通常情况下,每个CPU内核的shuffle分区数应该大约为2-3个。 3.调整并行度。并行度是指在Spark上运行的任务和数据的并发程度。较高的并行度可以提高Spark性能。通常情况下,并行度应该设置为CPU内核数的两倍以上。 4.调整序列化格式。可以通过改变序列化格式来提高性能,比如使用Kryo而不是默认的Java序列化格式。Kryo在序列化大型对象时比Java序列化更快。 综上所述,开发调优和资源调优是优化Spark性能的两个非常关键的方面。通过遵循最佳实践和设置合适的参数,可以使Spark应用程序在性能和资源使用方面发挥出最大的潜力,提高生产力和成果。 ### 回答3: Spark是一种强大的数据处理框架,需要高效的性能来完成各种任务。本篇文章将介绍一些关键的Spark性能优化指南——基础篇,包括开发调优、资源调优和设置参数。 开发调优 1. 使用高效的算法和数据结构 不同的算法和数据结构对于Spark作业的性能有着巨大的影响。了解每个任务所需的计算复杂度和数据大小,并对其进行优化是非常重要的。 2. 将代码逻辑转换为RDD操作 RDD操作是Spark的核心概念之一。将代码逻辑转换为RDD操作可以大幅提升Spark性能表现。因此,应该尽量使用Spark提供的各种高级API来进行开发,而不是去编写过于冗长的自定义代码。 3. 减小内存开销 为了让Spark性能保持稳定,开发者应该尽量减小内存占用。这包括压缩数据、使用序列化器等等。 资源调优 1. 配置适当的并行度 Spark作业的并行度决定了任务能够同时处理的数据量。错误的并行度设置可能会导致任务成功率降低或者资源利用不充分的情况。因此,开发者需要通过多次试验来找到适合自己任务的并行度。 2. 调整JVM内存 JVM内存的大小对于Spark作业的性能有着很大的影响。如果JVM内存设置过小,可能会导致堆的内存不足。反之,如果设置过大,可能会导致垃圾回收时间变长。因此,开发者应该根据任务的需求来调整JVM内存的大小。 设置参数 1. 启用动态分区(spark.sql.shuffle.partitions) 设置动态分区可以让Spark自动根据数据量来设置操作的分区数,从而提高作业性能。 2. 启用动态分配内存(spark.shuffle.service.enabled) Spark默认会预留50%的堆内存用于垃圾回收。但是对于内存资源较为紧缺的情况,这可能会影响到作业的性能。开启动态分配内存可以让Spark自动调整内存的使用率,优化作业的性能。 总结 本篇文章介绍了Spark性能优化的基础篇,包括开发调优、资源调优参数设置。这些方法可以极大地提高Spark作业的性能表现。然而,Spark性能优化是一个细节精益工程,需要开发者不断进行优化和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值