目錄
分割連續變量
標準化連續變量
分類
分割連續變量
我們經常處理高度非線性的連續特征,而且只用一個系數很難擬合到我們的模型中。
在這種情況下,可能很難只通過一個系數來解釋這樣一個特征與目標之間的關系。有時,將值劃分到離散的桶中是有用的。
首先,讓我們使用以下代碼創建一些偽造數據:
import numpy as np
x = np.arange(0, 100)
x = x / 100.0 * np.pi * 4
y = x * np.sin(x / 1.764) + 20.1234
現在,我們可以通過以下代碼創建一個 DataFrame:
schema = typ.StructType([typ.StructField('continuous_var', typ.DoubleType(), False)
])
data = spark.createDataFrame([[float(e), ] for e in y], schema=schema)
接下來,我們將使用 QuantileDiscretizer 模型將我們的連續變量分割成五個桶(numBuckets 參數):
discretizer = ft.QuantileDiscretizer(numBuckets=5, inputCol='continuous_var', outputCol='discretized')
讓我們看看我們得到了什么:
data_discretized = discretizer.fit(data).transform(data)
我們的函數現在看起來如下:
現在我們可以將這個變量當作分類變量,并使用 OneHotEncoder 進行編碼,以便將來使用。
標準化連續變量
標準化連續變量不僅有助于更好地理解特征之間的關系(因為解釋系數變得更容易),而且還有助于計算效率,并防止陷入一些數值陷阱。以下是如何在 PySpark ML 中進行操作。
首先,我們需要創建我們的連續變量的向量表示(因為它只是一個單獨的浮點數):
vectorizer = ft.VectorAssembler(inputCols=['continuous_var'], outputCol= 'continuous_vec')
接下來,我們構建我們的標準化器和管道。通過將 withMean 和 withStd 設置為 True,該方法將去除均值,并將方差縮放到單位長度:
normalizer = ft.StandardScaler(inputCol=vectorizer.getOutputCol(), outputCol='normalized', withMean=True,withStd=True
)
pipeline = Pipeline(stages=[vectorizer, normalizer])
data_standardized = pipeline.fit(data).transform(data)
這是轉換后的數據的樣子:
如你所見,數據現在圍繞 0 振蕩,具有單位方差(綠線)。
分類
到目前為止,我們只使用了 PySpark ML 中的 LogisticRegression 模型。在這一部分,我們將使用 RandomForestClassifier 再次模擬嬰兒的生存機會。
在我們可以做到這一點之前,我們需要將標簽特征轉換為 DoubleType:
import pyspark.sql.functions as func
births = births.withColumn('INFANT_ALIVE_AT_REPORT', func.col('INFANT_ALIVE_AT_REPORT').cast(typ.DoubleType())
)
births_train, births_test = births \.randomSplit([0.7, 0.3], seed=666)
現在我們已經將標簽轉換為雙精度,我們準備構建我們的模型。我們以與之前類似的方式進行,區別是我們將重用本章早期的編碼器和 featureCreator。numTrees 參數指定應該有多少決策樹在我們的隨機森林中,maxDepth 參數限制了樹的深度:
classifier = cl.RandomForestClassifier(numTrees=5, maxDepth=5, labelCol='INFANT_ALIVE_AT_REPORT')
pipeline = Pipeline(stages=[encoder,featuresCreator, classifier])
model = pipeline.fit(births_train)
test = model.transform(births_test)
現在讓我們來看看 RandomForestClassifier 模型與 LogisticRegression 模型相比表現如何:
evaluator = ev.BinaryClassificationEvaluator(labelCol='INFANT_ALIVE_AT_REPORT')
print(evaluator.evaluate(test, {evaluator.metricName: "areaUnderROC"}))
print(evaluator.evaluate(test, {evaluator.metricName: "areaUnderPR"}))
我們得到以下結果:
嗯,正如你看到的,結果比邏輯回歸模型好大約 3 個百分點。讓我們測試一下單棵樹的模型表現如何:
classifier = cl.DecisionTreeClassifier(maxDepth=5, labelCol='INFANT_ALIVE_AT_REPORT')
pipeline = Pipeline(stages=[encoder,featuresCreator, classifier])
model = pipeline.fit(births_train)
test = model.transform(births_test)
evaluator = ev.BinaryClassificationEvaluator(labelCol='INFANT_ALIVE_AT_REPORT')
print(evaluator.evaluate(test, {evaluator.metricName: "areaUnderROC"}))
print(evaluator.evaluate(test, {evaluator.metricName: "areaUnderPR"}))
前面的代碼給出了以下結果:
一點也不差!實際上,在精確度-召回率關系方面,它的表現比隨機森林模型更好,而且在 ROC 下面積方面只是稍微差一些。我們可能剛剛發現了一個贏家!
?