3、对数据进行清理与变换
采集上来的数据往往会有缺失值,或者说数据格式不符合特定机器学习算法的要求,因此需要进行资料的清理与转换。
对于缺失值,有的数值可以使用平均值替代;有的字段缺失可以删除整行记录。
对于机器学习算法,数据集中若有字符串类型的标签数据,往往需要进行数值化处理。
from pyspark.ml.feature import StringIndexer, VectorAssembler, VectorIndexer
df_train = spark.read.csv('./data/titanic-train.csv',header=True,inferSchema=True).cache()
#df_train.printSchema()
#print(df_train.count(),len(df_train.columns))
#891 12
#age缺失值,用平均值29.699替换,四舍五入
df_train = df_train.fillna({'Age': round(29.699,0)})
#用登录最多的港口'S'替换缺失值
df_train = df_train.fillna({'Embarked': 'S'})
#df_train = df_train.fillna({'Cabin': 'unknown'})
#删除列,对预测结果没有关系的列进行删除,以降低内存占用
df_train = df_train.drop("Cabin")
df_train = df_train.drop("Ticket")
labelIndexer = StringIndexer(inputCol="Embarked", outputCol="iEmbarked")
model = labelIndexer.fit(df_train)
df_train = model.transform(df_train)
#pyspark中借助StringIndexer将字符串类型的字段数值化
labelIndexer = StringIndexer(inputCol="Sex", outputCol="iSex")
#将labelIndexer 在数据集df_train上进行fit操作
#调用模型的fit()方法产生一个预测结果
model = labelIndexer.fit(df_train)
#对数据集df_train进行数据转换
df_train = model.transform(df_train)
#打印数值化后的数据集
df_train.show()
# 特征选择,选取数值类型的字段
features = ['Pclass', 'iSex', 'Age', 'SibSp', 'Parch', 'Fare', 'iEmbarked','Survived']
#对数据列进行过滤
train_features = df_train[features]
#打印显示前20条数据
train_features.show()
# train_labels = df_train['Survived']
# train_labels.show()
#将多个列(类型必须为数值)转换成一个向量列
df_assembler = VectorAssembler(inputCols=['Pclass', 'iSex', 'Age', 'SibSp', 'Parch', 'Fare', 'iEmbarked'], outputCol="features")
[3.0,0.0,22.0,1.0....]
df = df_assembler.transform(train_features)
#df["features"].show()-> TypeError: 'Column' object is not callable
df["features",].show()
df["Survived",].show()
只有高质量的数据,才能构建出高质量的机器学习模型,并用于生产环境。
4、认识pipeline
机器学习是一个任务流,可以使用pipeline将数据加载、清理、变形、训练和预测等过程有序组织到一起。
Transformer阶段,在dataframe对象上调用transform()方法;
Estimator阶段,调用fit()方法来生成预测结果。
from pyspark.ml import Pipeline
# 分类 逻辑回归
from pyspark.ml.classification import LogisticRegression
# 分词器
from pyspark.ml.feature import HashingTF, Tokenizer
#模拟训练数据,有PySpark的文本为1,其他为0
training = spark.createDataFrame([
(0, "Hello PySpark", 1.0),
(1, "Using Flink", 0.0),
(2, "PySpark 3.0", 1.0),
(3, "Test MySQL", 0.0)
], ["id", "text", "label"])
# pipeline 三个阶段: tokenizer -> hashingTF -> logR.
tokenizer = Tokenizer(inputCol="text", outputCol="words")
hashingTF = HashingTF(inputCol=tokenizer.getOutputCol(), outputCol="features")
logR = LogisticRegression(maxIter=10, regParam=0.001)
#用Pipeline方法将之前定义的三个阶段 tokenizer hashingTF logR 组装成一个pipeline
pipeline = Pipeline(stages=[tokenizer, hashingTF, logR])
#训练数据上进行pipeline fit操作,产生一个model
model = pipeline.fit(training)
# 2、测试集
test = spark.createDataFrame([
(4, "PySpark Pipeline"),
(5, "pipeline"),
(6, "PySpark python"),
(7, "julia c#")
], ["id", "text"])
#在测试集test上,用model执行transform操作,并预测出结果
prediction = model.transform(test)
#预测
selected = prediction.select("id", "text", "probability", "prediction")
for row in selected.collect():
tid, text, prob, prediction = row
print("(%d, %s) --> prediction=%f,prob=%s" \
% (tid, text, prediction,str(prob)))
#打印的结果如下
(4, PySpark Pipeline) --> prediction=1.000000,
prob=[0.029796174862816768,0.9702038251371833]
(5, pipeline) --> prediction=0.000000,
prob=[0.56611226449896,0.43388773550104]
(6, PySpark python) --> prediction=1.000000,
prob=[0.029796174862816768,0.9702038251371833]
(7, julia c#) --> prediction=0.000000,
prob=[0.56611226449896,0.43388773550104]
训练数据中的文本规律为,有pyspark这个单词的文本标签字段为1.0,其他为0.0。
在测试数据上的预测结果都和预期相符。