๋ฐฉ๊ธ PySpark http://dmlc.ml/2016/03/14/xgboost4j-portable-distributed-xgboost-in-spark-flink-and-dataflow.html ํตํฉ์ ๋ํ ๋ช ๊ฐ์ง ์์ฒญ์ด ์์์ ์์์ต๋๋ค.
๋๋ ๋ํ ๊ฐ์ ์ฃผ์ ์ ๋ํด ํ ๋ก ํ๋ ์ฌ์ฉ์๋ก๋ถํฐ ๋ช ๊ฐ์ง ์ด๋ฉ์ผ์ ๋ฐ์์ต๋๋ค.
์ด ์์ ์ ์ธ์ ์์ํ ์ง ์ฌ๋ถ์ ๋ํ ๋ ผ์๋ฅผ ์ฌ๊ธฐ์ ์์ํ๊ณ ์ถ์ต๋๋ค.
@tqchen @terrytangyuan
@CodingCat PySpark ์ปค๋ฎค๋ํฐ๊ฐ ์ผ๋ง๋ ํฐ์ง ์์ญ๋๊น? ๋๋ถ๋ถ์ ์ฌ๋๋ค์ Scala API๋ง ์ฌ์ฉํฉ๋๋ค. ๋ง์ ๊ฒ๋ค์ด ํ์ด์ฌ์์ ๋ค์ ๊ตฌํ๋์ด์ผ ํ๋ ๊ฒ ๊ฐ์ต๋๋ค - ๋ง์ฝ ์ ๊ฐ ํ๋ ธ๋ค๋ฉด ์ ๋ฅผ ๊ณ ์ณ์ฃผ์ธ์.
๋๋ PySpark๊ฐ ๋ฐ์ดํฐ ๊ณผํ์ ์ปค๋ฎค๋ํฐ์์ ๊ฝค ๋๋ฆฌ ํผ์ ธ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ฆ, ๋น ๋ฅธ ํ๋กํ ํ์ดํ ์๋๋ฆฌ์ค ๋ฑ์ ์๋ฏธํฉ๋๋ค. ๋ฐ์ดํฐ ๊ณผํ์๊ฐ pySpark๋ฅผ ์ฌ์ฉํ์ฌ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๋ ๋ง์ ์ฌ๋ก์ ๋ํด ๋ค์์ต๋๋ค.
๋ฐ๋ฉด์ ๋๋ถ๋ถ์ ํ๋ก๋์ ์์ค ์๋๋ฆฌ์ค๋ Scala API๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค(์ฌ๋๋ค์ด ๋๊ท๋ชจ ํ๋ก๋์ ์์ PySpark๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ํ๋๋ง ์๊ณ ์์ต๋๋ค).
์, ํ์ฌ Python API๊ฐ ๋๋ถ๋ถ์ ํ๋กํ ํ์ดํ ์๊ตฌ ์ฌํญ์ ์ฒ๋ฆฌํ ์ ์์ด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋ ๋ง์ ํ๋ก๋์ ์ค๋น๊ฐ ๋ ๊ฒ์ ์ํ ๋ ๋๋ ๊ฐ์ธ์ ์ผ๋ก Spark์ ๋ ๊ด์ฌ์ด ์์ต๋๋ค. ์๋ง๋ ์ฐ๋ฆฌ๋ ์ฌ๋๋ค์ด ๊ทธ๋ค์ ํ์์ ๋ํด ๋ ผ์ํ ์ ์๋๋ก ์ฌ๊ธฐ์ ํ ๋ก ์ ๋จ๊ฒจ์ผ ํ ๊ฒ์ ๋๋ค. ๊ทธ๋์ ํตํฉ์ ์ํ ์ ๊ทผ ๋ฐฉ์/์ถ์ /๋จ๊ณ์ ๋ํ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ ๊ณตํด ์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค.
์ปค๋ฎค๋ํฐ์์ ์ผ๋ถ ํ ๋ก ์ ๋ฐ๊ฒฌํ์ต๋๋ค.
http://apache-spark-developers-list.1001551.n3.nabble.com/Blocked-PySpark-changes-td19712.html
PySpark์ ๊ฐ๋ฐ์ด ๋ค์ฒ์ ธ ์๋ ๊ฒ ๊ฐ์ต๋๋ค...๋ค์ด์คํธ๋ฆผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก์ ์ ๋ PySpark ํตํฉ์ ์ ๋
ํ๊ธฐ ์ํด hold on
์ ํฌํํฉ๋๋ค.....
๋ค, ๋ฐ์ํ ๋ฌธ์ ๋ฅผ ๋๋ฒ๊น ํ๋ ๊ฒ๋ ์ด๋ ต์ต๋๋ค(์ ์ด๋ ์๋ ์ ์๋ํ์ ๋)...
๋ก๋๋งต(#873)์๋ ๋ถ์ฐ ํ์ด์ฌ์ด ๊ตฌํ๋์๋ค๊ณ ๋์ ์์ต๋๋ค. xgboost๊ฐ ํ์ด์ฌ์ผ๋ก hadoop ํด๋ฌ์คํฐ์์ ์คํํ ์ ์์์ ์๋ฏธํฉ๋๊น? (๋๋ pyspark๋ฅผ ์๋ฏธํ์ง ์์ต๋๋ค)
์, ๋งํฌ์ ๊ฒ์๋ ์๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
python์ผ๋ก hadoop ํด๋ฌ์คํฐ์์ xgboost๋ฅผ ์คํํ๋ ๊ฒ๊ณผ scala api๋ก hadoop ํด๋ฌ์คํฐ์์ xgboost๋ฅผ ์คํํ๋ ๊ฒ์ ์ฐจ์ด์ ์ ๋ฌด์์
๋๊น? ์ฃผ์ ์ฑ๋ฅ ์ฐจ์ด๊ฐ ์์ต๋๊น?
ํ๋ก๋์
๋ชจ๋ธ๋ก๋ pyspark๋ฅผ ์ฌ์ฉํ๋ ์ฌ๋๋ค์ด ์์ง ๋ง์ด ์๋ ๊ฒ ๊ฐ์์.
@yiming-chen xgboost4j-spark์ ๋ชฉํ๋ ๋์ผํ ํ์ดํ๋ผ์ธ์์ ETL๊ณผ ๋ชจ๋ธ ๊ต์ก์ ํตํฉํ๋ ๊ฒ์ ๋๋ค.
์ง๋ฌธ์ ์ฌ์ฉ์๊ฐ ETL์ ์ํํ ๋ ์ด๋ค ์ธ์ด๋ฅผ ์ฌ์ฉํ๋์ง์ ๋ํ ๊ฒ์ ๋๋ค. ๋ด ๊ด์ฐฐ๊ณผ ๊ฒฝํ์ ๋ฐ๋ฅด๋ฉด 95%์ ์ฌ์ฉ์๊ฐ scala๋ก ETL ์์คํ ์ ๊ตฌ์ถํ๊ณ ์์ต๋๋ค.
@CodingCat 95% ํต๊ณ๋ฅผ ์ด๋์ ์ป์๋์ง ๋ชจ๋ฅด๊ฒ ์ง๋ง PySpark๋ ํ์คํ ์ ๊ฒฝํ์ ๋๋ฆฌ ์ฌ์ฉ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ฐ๋ฆฌ๋ Airflow๋ฅผ ํตํฉํ์ฌ ํ์ดํ๋ผ์ธ์ ๋ํ ์์ ์ ์์ฝํ๋ ค๊ณ ํ๊ณ Python์ด ์ด ์ํฉ์ ์ ํฉํ ๊ฒ์ ๋๋ค.
@berch PySpark๋ ๊ทํ๊ฐ ๋๋ฆฌ ์ฌ์ฉํ๊ณ ์์ผ๋ฉฐ ๊ธฐ๋ฅ์ ํตํฉํ ์์ ์ ๋๋ค... ์ ๊ฐ ๋งํ ๊ฒ๊ณผ ๊ด๋ จ์ด ์์ต๋๊น?
@CodingCat @tqchen ๋ฐ์ดํฐ ๊ณผํ ์ปค๋ฎค๋ํฐ๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก PySpark์์ ๊ตฌํ๋ XGboost์ ์ด์ ์ ํ์คํ ๋๋ฆด ๊ฒ์ ๋๋ค.
PR์ ๋ณด๋ด์ฃผ์ญ์์ค. ๋น์ฉ์ ์ฐพ์ ์ ์์ต๋๋ค.
๋ค์ ์ค๋ ๋๋ก ๋์๊ฐ์ง ์๋๋ก ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๋ก ์ผ๋ก โโํ ๋ก ์ ๋ง๋ฌด๋ฆฌํ๊ฒ ์ต๋๋ค.
๋๋ ๊ฐ์ธ์ ์ผ๋ก PySpark๋ฅผ ํตํฉํ๊ธฐ ์ํ ์ด ๋ ธ๋ ฅ์ ๊ณ์ํ๊ธฐ ์ํด ํฌํํ์ง ์์ ๊ฒ์ ๋๋ค(ํ์ฌ๋ก์๋)
๋ค๋ฅธ ์ฌ๋์ด ์ด์ ๊ธฐ์ฌํ๋ ๊ฒ์ ํ์ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ์ต์ํ ๋ค์ ์ฌํญ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค.
๋ค๋ฅธ ํ์ด์ฌ ํจํค์ง๋ฅผ ์๊ฐํ์ง ๋ง์ญ์์ค
ํตํฉ์ ๊ตฌํํ ๋ ํ์ฌ Python API์ ๋ํ ์ด์ ๋ฒ์ ๊ณผ์ ํธํ์ฑ
pyspark ML์ ๋ค์ณ์ง ๊ธฐ๋ฅ ์ฒ๋ฆฌ
๊ทธ๋ ๋ค๋ฉด pyspark๋ฅผ ์ฌ์ฉํ์ฌ XGBoost-spark ๋ชจ๋ธ์ ๋ก๋ํ ์ ์์ต๋๊น? @์ฝ๋ฉ์บฃ
๋ฐ๋ผ์ ์ค์ ๋ก scala XGBoost
๋ PySpark JavaEstimator
API์์ ๋ ๊ณ ํต์ค๋ฝ๊ฒ ๋ํ๋ ์ ์์ต๋๋ค. ๋๋ ์กฐ๊ธ ๋์๊ณ ๋ค์๊ณผ ๊ฐ์ ํ๋กํ ํ์
์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
from pyspark.ml.wrapper import JavaEstimator, JavaModel
from pyspark.ml.param.shared import *
from pyspark.ml.util import *
from pyspark.context import SparkContext
class XGBoost(JavaEstimator, JavaMLWritable, JavaMLReadable, HasRegParam, HasElasticNetParam):
def __init__(self, paramMap = {}):
super(XGBoost, self).__init__()
scalaMap = SparkContext._active_spark_context._jvm.PythonUtils.toScalaMap(paramMap)
self._java_obj = self._new_java_obj(
"ml.dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
self._defaultParamMap = paramMap
self._paramMap = paramMap
def setParams(self, paramMap = {}):
return self._set(paramMap)
def _create_model(self, javaTrainingData):
return JavaModel(javaTrainingData)
์์ง ์์
์ด ํ์ํ๋ค๊ณ ์๊ฐํ์ง๋ง PySpark์์ Xgboost
๋ฅผ ์คํํ ์ ์์์ต๋๋ค.
Wieslaw๋ XGBoost PySpark ๋ํผ์ ๋ํ ์ฝ๋ ์กฐ๊ฐ์ ๊ณต์ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ์ ์ ํ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ XGBoost ํด๋์ค๋ฅผ ํธ์ถํ๋ ์ฝ๋๋ฅผ ๊ณต์ ํ ์ ์์ต๋๊น?
๊ฐ์ฌ ํด์
@wpopielarski ๋น์ ์ด ํ ๋ฉ์ง ์ผ์ ๋๋ค. ํ์ํ ๋งค๊ฐ๋ณ์์ ํจ๊ป XGBoost๋ฅผ ํธ์ถํ๋ ์ฝ๋๋ฅผ ๊ณต์ ํ ์ ์์ต๋๊น? ํฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค!
์ด๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
from app.xgboost import XGBoost
xgboost_params = {
"eta" : 0.023,
"max_depth" : 10,
"min_child_weight" : 0.3,
"subsample" : 0.7,
"colsample_bytree" : 0.82,
"colsample_bylevel" : 0.9,
"base_score" : base_score,
"eval_metric" : "auc",
"seed" : 49,
"silent" : 1,
"objective" : "binary:logistic",
"round" : 10,
"nWorkers" : 2,
"useExternalMemory" : True
}
xgboost_estimator = XGBoost.XGBoost(xgboost_params)
...
model = xgboost_estimator.fit(data)
์ ์ ํ PySpark ์ง์์ผ๋ก PR์ ํ๋ ๋ฐ ๊ฐ๊น์์ง๊ณ ์์ต๋๋ค.
@thesuperzapper , ํ๋ฅญํฉ๋๋ค!
ํฌ์ฅํ๋๋ฐ ์ผ๋ง๋ ๊ฑธ๋ฆด ๊ฒ ๊ฐ๋์? ์งํํ๋ ๋์ ํต์ฐฐ๋ ฅ์ ๊ณต์ ํ์ญ์์ค.
๊ฐ์ฌ ํด์!
์๋
ํ์ธ์, ๊ด์ฌ ์๋ ์ฌ๋์ด ์์ผ๋ฉด ์ฝ๊ฒ ์ฌ์ฉ์ ์ง์ ํ ์ ์๋๋ก ParamGridBuilder
๋ก ๊ฐ๋จํ ๋ฒ์ ์ ์์ฑํฉ๋๋ค.
mkdir -p ml/dmlc/xgboost4j/scala
ํจํค์ง ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ญ๋๋ค.ml/dmlc/xgboost4j/scala/spark.py
์๋ 2๊ฐ์ ๋ณต์ฌ ์ฝ๋from pyspark.ml.classification import JavaClassificationModel, JavaMLWritable, JavaMLReadable, TypeConverters, Param, \
Params, HasFeaturesCol, HasLabelCol, HasPredictionCol, HasRawPredictionCol, SparkContext
from pyspark.ml.wrapper import JavaModel, JavaWrapper, JavaEstimator
class XGBParams(Params):
'''
'''
eta = Param(Params._dummy(), "eta",
"step size shrinkage used in update to prevents overfitting. After each boosting step, we can directly get the weights of new features. and eta actually shrinks the feature weights to make the boosting process more conservative",
typeConverter=TypeConverters.toFloat)
max_depth = Param(Params._dummy(), "max_depth",
"maximum depth of a tree, increase this value will make the model more complex / likely to be overfitting. 0 indicates no limit, limit is required for depth-wise grow policy.range: [0,โ]",
typeConverter=TypeConverters.toInt)
min_child_weight = Param(Params._dummy(), "min_child_weight",
"minimum sum of instance weight (hessian) needed in a child. If the tree partition step results in a leaf node with the sum of instance weight less than min_child_weight, then the building process will give up further partitioning. In linear regression mode, this simply corresponds to minimum number of instances needed to be in each node. The larger, the more conservative the algorithm will berange: [0,โ]",
typeConverter=TypeConverters.toFloat)
max_delta_step = Param(Params._dummy(), "max_delta_step",
"Maximum delta step we allow each treeโs weight estimation to be. If the value is set to 0, it means there is no constraint. If it is set to a positive value, it can help making the update step more conservative. Usually this parameter is not needed, but it might help in logistic regression when class is extremely imbalanced. Set it to value of 1-10 might help control the update.",
typeConverter=TypeConverters.toInt)
subsample = Param(Params._dummy(), "subsample",
"subsample ratio of the training instance. Setting it to 0.5 means that XGBoost randomly collected half of the data instances to grow trees and this will prevent overfitting.",
typeConverter=TypeConverters.toFloat)
colsample_bytree = Param(Params._dummy(), "colsample_bytree",
"subsample ratio of columns when constructing each tree",
typeConverter=TypeConverters.toFloat)
colsample_bylevel = Param(Params._dummy(), "colsample_bylevel",
"subsample ratio of columns for each split, in each level.",
typeConverter=TypeConverters.toFloat)
max_leaves = Param(Params._dummy(), "max_leaves",
"Maximum number of nodes to be added. Only relevant for the โlossguideโ grow policy.",
typeConverter=TypeConverters.toInt)
def __init__(self):
super(XGBParams, self).__init__()
class XGBoostClassifier(JavaEstimator, JavaMLWritable, JavaMLReadable, XGBParams,
HasFeaturesCol, HasLabelCol, HasPredictionCol, HasRawPredictionCol):
def __init__(self, paramMap={}):
super(XGBoostClassifier, self).__init__()
scalaMap = SparkContext._active_spark_context._jvm.PythonUtils.toScalaMap(paramMap)
self._java_obj = self._new_java_obj("ml.dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
self._defaultParamMap = paramMap
self._paramMap = paramMap
def setParams(self, paramMap={}):
return self._set(paramMap)
def _create_model(self, java_model):
return XGBoostClassificationModel(java_model)
class XGBoostClassificationModel(JavaModel, JavaClassificationModel, JavaMLWritable, JavaMLReadable):
def getBooster(self):
return self._call_java("booster")
def saveBooster(self, save_path):
jxgb = JavaWrapper(self.getBooster())
jxgb._call_java("saveModel", save_path)
@AakashBasuRZT @haiy , ์ฐ๋ฆฌ๋ ํ์ฌ ๋ฌธ์ #3370์์ ์ด์ ๋ํด ์ ๋๋ก ์์ ํ๊ณ ์์ผ๋ฉฐ PR #3376์ด ์ด๊ธฐ ์ง์์ ์ ๊ณตํ๊ณ ์์ต๋๋ค.
@haiy ์ผ๋ถ ์์ ๋ฐ์ดํฐ ์ธํธ์ ๋ถ๋ฅ๊ธฐ์ ๋ง๋ ์ฝ๋ ์ค๋ํซ์ ๋ณด์ฌ ์ฃผ์๊ฒ ์ต๋๊น? ๋๋ ๋น์ ์ด ์์ฝ ํ 1๊ณผ 2๋ฅผ ๋ฐ๋์ง๋ง ์ธ ๋ฒ์งธ ์์ ์ ์ดํดํ ์ ์์ต๋๋ค.
@sagnik-rzt ์ด ์ํ์ ํ์ธ
@haiy ๋๋ ์ด๊ฒ์ ์คํํ๋ ค๊ณ ํฉ๋๋ค :
import pyspark
import pandas as pd
from dmlc.xgboost4j.scala.spark import XGBoostClassifier
from sklearn.utils import shuffle
sc = pyspark.SparkContext('local[2]')
spark = pyspark.sql.SparkSession(sc)
df = pd.DataFrame({'x1': range(10), 'x2': [10] * 10, 'y': shuffle([0 for i in range(5)] + [1 for i in range(5)])})
sdf = spark.createDataFrame(df)
X = sdf.select(['x1', 'x2'])
Y = sdf.select(['y'])
print(X.show(5))
params = {'objective' :'binary:logistic', 'n_estimators' : 10, 'max_depth' : 3, 'learning_rate' : 0.033}
xgb_model = XGBoostClassifier(params)
์ด ์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค.
Traceback (most recent call last):
File "/home/sagnikb/PycharmProjects/auto_ML/pyspark_xgboost.py", line 20, in <module>
xgb_model = XGBoostClassifier(params)
File "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", line 47, in __init__
self._java_obj = self._new_java_obj("ml.dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
File "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", line 63, in _new_java_obj
return java_obj(*java_args)
TypeError: 'JavaPackage' object is not callable
Error in sys.excepthook:
Traceback (most recent call last):
File "/home/sagnikb/PycharmProjects/auto_ML/pyspark_xgboost.py", line 20, in <module>
xgb_model = XGBoostClassifier(params)
File "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", line 47, in __init__
self._java_obj = self._new_java_obj("ml.dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
File "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", line 63, in _new_java_obj
return java_obj(*java_args)
TypeError: 'JavaPackage' object is not callable
Exception ignored in: <bound method JavaParams.__del__ of XGBoostClassifier_4f9eb5d1388e9e1424a4>
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", line 105, in __del__
SparkContext._active_spark_context._gateway.detach(self._java_obj)
File "/usr/local/lib/python3.6/dist-packages/py4j/java_gateway.py", line 1897, in detach
java_object._detach()
AttributeError: 'NoneType' object has no attribute '_detach'
ํ๊ฒฝ:
ํ์ด์ฌ 3.6
์คํํฌ 2.3
์ค์นผ๋ผ 2.11
@sagnik-rzt
ํ์คํ์ง ์์ง๋ง ์คํํฌ ํด๋์ค ๊ฒฝ๋ก์ deps์ ํจ๊ป xgboost-spark.jar์ ์ถ๊ฐํฉ๋๊น?
@wpopielarski ์๋ ํ์ธ์, ์ ๋ ๊ทธ๋ ๊ฒ ํ์ง ์์์ต๋๋ค. ๊ทธ jar ํ์ผ์ ์ด๋์์ ์ฐพ์ ์ ์๋์ง ์ ์ ์์ต๋๊น?
@sagnik-rzt ์๋
ํ์ธ์, ์ฌ๊ธฐ ์์ ํญ์๋ฆฌ๋ฅผ ๋ค์ด๋ก๋ . ์ฃ์กํฉ๋๋ค. ๋ฐฉ๊ธ ๋ด ํญ์๋ฆฌ๊ฐ mac์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ ๋์์์ ๋ฐ๊ฒฌํ์ต๋๋ค. ๊ตฌ์ถํด ๋ณด์ธ์. ๊ทธ๋ฆฌ๊ณ $SPARK_HOME/jars
์ ๊ฐ์ด spark deps dir์ ๋ฃ์ผ์ญ์์ค.
jvm-packages/xgboost-spark/target
์ ๋์ ๋ฑ๋ฑํ ํญ์๋ฆฌ๋ฅผ ๋ง๋๋ maven ๋ฐ assembly
ํ๋กํ์ ์ฌ์ฉํ์ฌ ์ง์ ๋น๋ํด์ผ ํฉ๋๋ค.
@sagnik-rzt ๋ฌด์์ ํ๋ ค๋์ง ํ์คํ์ง ์์ง๋ง OS์ฉ ๋ฑ๋ฑํ ํญ์๋ฆฌ๋ฅผ ๋ง๋ค๋ ค๋ฉด dmlc xgboost github ํ๋ก์ ํธ๋ฅผ ๋ณต์ ํ๊ณ cd๋ฅผ jvm-packages๋ก ๋ณต์ ํ๊ณ assemby
ํ๋กํ๋ก mvn์ ์คํํ์ญ์์ค. Gradle ๋น๋ ํ์ผ์ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์ ๋ชจ๋ฆ
๋๋ค.
์, ์ข
์์ฑ์ด ์๋ ๋ฑ๋ฑํ ํญ์๋ฆฌ๋ฅผ ๋ง๋ ๋ค์ $SPARK_HOME/jars์ ๋ณต์ฌํ์ฌ ๋ถ์ฌ๋ฃ์์ต๋๋ค.
๊ทธ๋ฌ๋ ๋์ผํ ์์ธ๊ฐ ๊ณ์ ์ ์ฉ๋ฉ๋๋ค.
Traceback (most recent call last):
File "/home/sagnikb/PycharmProjects/xgboost/test_import.py", line 21, in <module>
clf = xgb(params)
File "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", line 48, in __init__
self._java_obj = self._new_java_obj("dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
File "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", line 63, in _new_java_obj
return java_obj(*java_args)
TypeError: 'JavaPackage' object is not callable
์ฃ์กํ์ง๋ง ์ผ๋ถ IDE ํ๋ก์ ํธ์์ ๋ก์ปฌ๋ก ํด๋ฌ์คํฐ์์ ์คํํฉ๋๊น? ๋น์ ์ด์๋ ๊ฒฝ์ฐ
spark-submit์ ์ฌ์ฉํ์ฌ --jars ์ค์์น์ deps๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
2018-06-29 14:30 GMT+02:00 sagnik-rzt [email protected] :
์ข์, ์์กด์ฑ์ด ์๋ ๋ฑ๋ฑํ ํญ์๋ฆฌ๋ฅผ ๋ง๋ ๋ค์ ๋ณต์ฌํ์ฌ ๋ถ์ฌ๋ฃ์์ต๋๋ค.
$SPARK_HOME/jars์.
๊ทธ๋ฌ๋ ๋์ผํ ์์ธ๊ฐ ๊ณ์ ์ ์ฉ๋ฉ๋๋ค.์ญ์ถ์ (๊ฐ์ฅ ์ต๊ทผ ํธ์ถ ๋ง์ง๋ง):
ํ์ผ "/home/sagnikb/PycharmProjects/xgboost/test_import.py", 21ํ,
clf = xgb(๋งค๊ฐ๋ณ์)
ํ์ผ "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", 48ํ, __init__
self._java_obj = self._new_java_obj("dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
ํ์ผ "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", 63ํ, _new_java_obj
๋ฐํ java_obj(*java_args)
TypeError: 'JavaPackage' ๊ฐ์ฒด๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.โ
๋น์ ์ด ์ธ๊ธ๋์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/dmlc/xgboost/issues/1698#issuecomment-401339910 ๋๋ ์์๊ฑฐ
์ค๋ ๋
https://github.com/notifications/unsubscribe-auth/ALEzS3JmKjO0AZ6JMzcixwCce0_3zRM0ks5uBh3ogaJpZM4KgAY_
.
์ ๋ ํ์ฌ #3376์ ์๋ก์ด spark ๋ธ๋์น๋ก ๋ฆฌ๋ฒ ์ด์คํ๋ ์์ ์ ํ๊ณ ์์ต๋๋ค. ๊ทธ๋์ ๋ช๋ช ์ฌ๋๋ค์ด XGBoost-0.72์์ ํ์ฌ ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์ง๋ฌธํ์ต๋๋ค.
๋ค์์ XGBoost-0.72์ฉ pyspark ์ฝ๋๊ฐ ํฌํจ๋ zip ํ์ผ์
๋๋ค.
๋ค์ด๋ก๋: sparkxgb.zip
๋ค์ ์์ ๋ง ํ๋ฉด ๋ฉ๋๋ค.
--jars
๋๋ spark.jars
๊ตฌ์ฑ ์ฌ์ฉ).sc.addPyFile("hdfs:///XXXX/XXXX/XXXX/sparkxgb.zip")
sample_binary_classification_data.txt
์ ๋๋ฌ ๊ฐ๋ฅํ ์์น๋ก ์ด๋ํ๋ค๊ณ ๊ฐ์ ํ๋ฉด ์ผ๋ฐ์ ์ผ๋ก $SPARK_HOME/data/mllib/sample_binary_classification_data.txt
)from sparkxgb import XGBoostEstimator
# Load Data
dataPath = "sample_binary_classification_data.txt"
dataDF = spark.read.format("libsvm").load(dataPath)
# Split into Train/Test
trainDF, testDF = dataDF.randomSplit([0.8, 0.2], seed=1000)
# Define and train model
xgboost = XGBoostEstimator(
# General Params
nworkers=1, nthread=1, checkpointInterval=-1, checkpoint_path="",
use_external_memory=False, silent=0, missing=float("nan"),
# Column Params
featuresCol="features", labelCol="label", predictionCol="prediction",
weightCol="weight", baseMarginCol="baseMargin",
# Booster Params
booster="gbtree", base_score=0.5, objective="binary:logistic", eval_metric="error",
num_class=2, num_round=2, seed=None,
# Tree Booster Params
eta=0.3, gamma=0.0, max_depth=6, min_child_weight=1.0, max_delta_step=0.0, subsample=1.0,
colsample_bytree=1.0, colsample_bylevel=1.0, reg_lambda=0.0, alpha=0.0, tree_method="auto",
sketch_eps=0.03, scale_pos_weight=1.0, grow_policy='depthwise', max_bin=256,
# Dart Booster Params
sample_type="uniform", normalize_type="tree", rate_drop=0.0, skip_drop=0.0,
# Linear Booster Params
lambda_bias=0.0
)
xgboost_model = xgboost.fit(trainDF)
# Transform test set
xgboost_model.transform(testDF).show()
# Write model/classifier
xgboost.write().overwrite().save("xgboost_class_test")
xgboost_model.write().overwrite().save("xgboost_class_test.model")
๋ฉ๋ชจ:
from sparkxgb.pipeline import XGBoostPipeline,XGBoostPipelineModel
์ ํจ๊ป ์์ ๋ ํ์ดํ๋ผ์ธ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํฉ๋๋ค.@thesuperzapper jupyter ๋ ธํธ๋ถ์์ pyspark๋ก ์ด๊ฒ์ ํ ์คํธํ๋ ค๊ณ ํฉ๋๋ค.
๋ด ์์คํ
:
ํ์ด์ฌ 3.6.1
xg๋ถ์คํธ 0.72
์คํํฌ 2.2.0
์๋ฐ 1.8
์ค์นผ๋ผ 2.12
XGBoostEstimator๋ฅผ ๋ก๋ํ๋ ค๊ณ ํ ๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋ํ๋ฉ๋๋ค.
Exception in thread "Thread-19" java.lang.NoClassDefFoundError: ml/dmlc/xgboost4j/scala/EvalTrait
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetPublicMethods(Class.java:2902)
at java.lang.Class.getMethods(Class.java:1615)
at py4j.reflection.ReflectionEngine.getMethodsByNameAndLength(ReflectionEngine.java:345)
at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:305)
at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:326)
at py4j.Gateway.invoke(Gateway.java:272)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:214)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ClassNotFoundException: ml.dmlc.xgboost4j.scala.EvalTrait
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 12 more
์ด๊ฒ์ ๋ฒ๊ทธ์ ๋๊น ์๋๋ฉด ๋ช ๊ฐ์ง ์๊ตฌ ์ฌํญ์ ๋์น๊ณ ์์ต๋๊น?
@BogdanCojocar xgboost ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋๋ฝ๋ ๊ฒ ๊ฐ์ต๋๋ค.
xgboost๊ฐ ์ ๋๋ก ์๋ํ๋ ค๋ฉด ๋ค์ ๋ ๋ณ์ด ๋ชจ๋ ํ์ํฉ๋๋ค.
ํด๋น maven ๋งํฌ์์ ํ์ํ jar๋ฅผ ๋ค์ด๋ก๋ํ ์ ์์ต๋๋ค.
@superzapper๋ ๊ฐ์ฌํฉ๋๋ค. ์ ์๋ํฉ๋๋ค. pyspark์ ๋ํ ์ด ํตํฉ์ด ํ๋ฅญํฉ๋๋ค!
Python ๋ชจ๋์ ๋ก๋ํ๊ธฐ ์ํด ํ๋ จ๋ ๋ชจ๋ธ์ ๋ถ์คํฐ์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์ ์์ด ์์ต๋๊น?
@ericwang915 ์ผ๋ฐ์ ์ผ๋ก ๋ค๋ฅธ XGBoost ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ํธ ์ด์ฉ๋๋ ๋ชจ๋ธ์ ์ป์ผ๋ ค๋ฉด ๋ชจ๋ธ ๊ฐ์ฒด์ .booster.saveModel("XXX/XXX")
๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ฌ๊ธฐ์ XXX๋ Spark ๋๋ผ์ด๋ฒ์ ๋ก์ปฌ(๋น HDFS) ๊ฒฝ๋ก์
๋๋ค. ๋ค๋ฅธ ์ ์ฅ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค(์ฐธ์กฐ: #2480).
๊ทธ๋ฌ๋ ํด๋น ๋ฒ์ ์ ๋ํผ์์ ์ ์ฅ ๊ธฐ๋ฅ์ ํธ์ถํ๋ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ์์์ต๋๋ค. ์๊ฐ์ด ๋๋ฉด ๋ด์ผ ์ถ๊ฐํ๊ฒ ์ต๋๋ค. (์ ๋ ๋ด์ง๋๋์ ์ด๊ณ ์์ต๋๋ค... ๊ทธ๋์ ์๊ฐ๋)
๊ฐ์ฌํฉ๋๋ค. ๊ทธ๊ฑด ๊ทธ๋ ๊ณ , ํ๋ จ ๊ณผ์ ์์ ๋ฌด์์ด 1๋ก ์ค์ ๋์ด ์์ด๋ ํ๊ฐ ์งํ์ ๋ถ์คํ ๋ผ์ด๋๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ก๊ทธ๊ฐ ์์ต๋๋ค.
@superzapper ์ง์์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. pyspark์์ xgboost ๋ชจ๋ธ์ ํ๋ จ/์ ์ฅํ๋ผ๋ ์ง์๋ฅผ ๋ฐ๋ฅผ ์ ์์์ต๋๋ค. (scala)getFeatureScore()์ ๊ฐ์ ๋ค๋ฅธ xgboost ๋ชจ๋ธ ํจ์์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์ด๋์ด๊ฐ ์์ต๋๊น?
@ccdtzccdtz ํ์ฌ 0.8์์ Spark API๊ฐ ํฌ๊ฒ ๋ณ๊ฒฝ๋์๊ธฐ ๋๋ฌธ์ pyspark ๋ํผ๋ฅผ ๋ค์ ๋ฐฐ์ ํ๊ณ ์์ต๋๋ค. ์๋ฃ๋๋ฉด Spark Scala API์ ๊ธฐ๋ฅ ํจ๋ฆฌํฐ๋ฅผ ๊ฐ๋ ๊ฒ์ด ๋ชฉํ์ ๋๋ค.
์ด๊ธฐ pyspark ๋ํผ์์ ๊ธฐ๋ณธ ๋ถ์คํฐ ๋ฉ์๋๋ฅผ ๋
ธ์ถํ์ง ์์์ง๋ง Spark Scala API๋ฅผ ์ฌ์ฉํ๋ฉด xgboost_model_object.nativeBooster.getFeatureScore(
ํธ์ถํ์ฌ ํ์์ฒ๋ผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
2๋ฒ ์ด์ ์คํํ๋ฉด pyspark์ XGBoost๊ฐ ์ง์์ ์ผ๋ก ์คํจํ๋ ๊ฒ์ ๋ณด์์ต๋๋ค. ๋์ผํ ์ฝ๋๋ก ๋์ผํ ๋ฐ์ดํฐ ์ธํธ์์ ์คํ ์ค์ ๋๋ค. ์ฒ์์๋ ์ฑ๊ณตํ์ง๋ง ๋ ๋ฒ์งธ์๋ ์คํจํฉ๋๋ค. Spark 2.3์์ XGBoost 0.72๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ์์ ์ ๋ค์ ์ฑ๊ณต์ ์ผ๋ก ์คํํ๋ ค๋ฉด pyspark ์ ธ์ ๋ค์ ์์ํด์ผ ํฉ๋๋ค.
๊ต์ก ๋ชฉ์ ์ผ๋ก xgboost.trainWithDataFrame์ ์ฌ์ฉํฉ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ๋ณธ ์ฌ๋์ด ์์ต๋๊น?
์๋
ํ์ธ์ @thesuperzapper
๋น์ ์ด ์ฒ๋ฐฉํ ๊ฒ์ ๋จ์ผ ์์
์ ๋
ธ๋์์ ์๋ํฉ๋๋ค.
๊ทธ๋ฌ๋ ๋ ์ด์์ ์์
์(์ด ๊ฒฝ์ฐ 3๊ฐ)๋ฅผ ์ฌ์ฉํ์ฌ pyspark xgboost๋ฅผ ์คํํ๋ ค๊ณ ํ๋ฉด ์คํ๊ธฐ๊ฐ ์ ํด ์ํ๊ฐ ๋๊ณ ์ ์ ํ ์ข
๋ฃ๋ฉ๋๋ค.
์ด๊ฒ์ Titanic ๋ฐ์ดํฐ ์ธํธ(์์ ๋ฐ์ดํฐ ์ธํธ)์์ ์คํํ๋ ค๊ณ ํ๋ ์ฝ๋์
๋๋ค.
from pyspark.sql.session import SparkSession
from pyspark.sql.types import *
from pyspark.ml.feature import StringIndexer, VectorAssembler
from pyspark.ml import Pipeline
from pyspark.sql.functions import col
spark = SparkSession\
.builder\
.appName("PySpark XGBOOST Titanic")\
.getOrCreate()
#spark.sparkContext.addPyFile("../sparkxgb.zip")
from automl.sparkxgb import XGBoostEstimator
schema = StructType(
[StructField("PassengerId", DoubleType()),
StructField("Survival", DoubleType()),
StructField("Pclass", DoubleType()),
StructField("Name", StringType()),
StructField("Sex", StringType()),
StructField("Age", DoubleType()),
StructField("SibSp", DoubleType()),
StructField("Parch", DoubleType()),
StructField("Ticket", StringType()),
StructField("Fare", DoubleType()),
StructField("Cabin", StringType()),
StructField("Embarked", StringType())
])
df_raw = spark\
.read\
.option("header", "true")\
.schema(schema)\
.csv("titanic.csv")
df = df_raw.na.fill(0)
sexIndexer = StringIndexer() \
.setInputCol("Sex") \
.setOutputCol("SexIndex") \
.setHandleInvalid("keep")
cabinIndexer = StringIndexer() \
.setInputCol("Cabin") \
.setOutputCol("CabinIndex") \
.setHandleInvalid("keep")
embarkedIndexer = StringIndexer() \
.setInputCol("Embarked") \
.setOutputCol("EmbarkedIndex") \
.setHandleInvalid("keep")
vectorAssembler = VectorAssembler()\
.setInputCols(["Pclass", "SexIndex", "Age", "SibSp", "Parch", "Fare", "CabinIndex", "EmbarkedIndex"])\
.setOutputCol("features")
xgboost = XGBoostEstimator(nworkers=2,
featuresCol="features",
labelCol="Survival",
predictionCol="prediction"
)
pipeline = Pipeline().setStages([sexIndexer, cabinIndexer, embarkedIndexer, vectorAssembler, xgboost])
trainDF, testDF = df.randomSplit([0.8, 0.2], seed=24)
model =pipeline.fit(trainDF)
print(trainDF.schema)
๋ค์์ ์คํ ์ถ์ ์
๋๋ค.
Tracker started, with env={DMLC_NUM_SERVER=0, DMLC_TRACKER_URI=172.16.1.5, DMLC_TRACKER_PORT=9093, DMLC_NUM_WORKER=3}2018-09-04 08:52:55 ERROR TaskSchedulerImpl:70 - Lost executor 0 on 192.168.49.43: Remote RPC client disassociated. Likely due to containers exceeding thresholds, or network issues. Check driver logs for WARN messages.2018-09-04 08:52:55 ERROR AsyncEventQueue:91 - Interrupted while posting to TaskFailedListener. Removing that listener.java.lang.InterruptedException: ExecutorLost during XGBoost Training: ExecutorLostFailure (executor 0 exited caused by one of the running tasks) Reason: Remote RPC client disassociated. Likely due to containers exceeding thresholds, or network issues. Check driver logs for WARN messages. at org.apache.spark.TaskFailedListener.onTaskEnd(SparkParallelismTracker.scala:116) at org.apache.spark.scheduler.SparkListenerBus$class.doPostEvent(SparkListenerBus.scala:45) at org.apache.spark.scheduler.AsyncEventQueue.doPostEvent(AsyncEventQueue.scala:37) at org.apache.spark.scheduler.AsyncEventQueue.doPostEvent(AsyncEventQueue.scala:37) at org.apache.spark.util.ListenerBus$class.postToAll(ListenerBus.scala:91)
์คํ๊ธฐ๊ฐ ๋ค์์์ ๋ฉ์ท์ต๋๋ค.
org.apache.spark.RDD.foreachPartition(RDD.scala:927)
ml.dmlc.xgboost4j.scala.spark.XGBoost$$anonfun$trainDistributed$4$$anon$1.run(XGBoost.scala:348)
ํ๊ฒฝ: Python 3.5.4, Spark ๋ฒ์ 2.3.1, Xgboost 0.72
xgboost ๋ฐ spark ๊ตฌ์ฑ์ ๊ณต์ ํ ์ ์์ต๋๊น? ์ผ๋ง๋
์์
์(xgboost ์์
์), ์คํํฌ ์คํ๊ธฐ, ์ฝ์ด ๋ฑ
-๋ํด
2018๋ 9์ 4์ผ ํ์์ผ ์ค์ 5:03 sagnik-rzt [email protected]์์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
์๋ ํ์ธ์ @thesuperzapper https://github.com/thesuperzapper
๋น์ ์ด ์ฒ๋ฐฉํ ๊ฒ์ ๋จ์ผ ์์ ์ ๋ ธ๋์์ ์๋ํฉ๋๋ค.
๊ทธ๋ฌ๋ ๋ ์ด์์ ์ฌ์ฉํ์ฌ pyspark xgboost๋ฅผ ์คํํ๋ ค๊ณ ํ ๋
์์ ์, ์คํ์๋ ์ ํด ์ํ๊ฐ ๋๊ณ ์ ์ ํ ์ข ๋ฃ๋ฉ๋๋ค.
๋ค์์ ์คํ ์ถ์ ์ ๋๋ค.
'''
์ถ์ ๊ธฐ๊ฐ ์์๋จ, env={DMLC_NUM_SERVER=0, DMLC_TRACKER_URI=172.16.1.5,
DMLC_TRACKER_PORT=9093, DMLC_NUM_WORKER=3}2018-09-04 08:52:55 ์ค๋ฅ
TaskSche dulerImpl:70 - 192.168.49.43์์ ์คํ๊ธฐ 0 ์์ค: ์๊ฒฉ RPC
ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ ํด์ ๋์์ต๋๋ค. ์๊ณ๊ฐ์ ์ด๊ณผํ๋ ์ปจํ ์ด๋๋ก ์ธํ ๊ฒ์ผ ์ ์์ต๋๋ค.
๋คํธ์ํฌ ๋ฌธ์ . WARN ๋ฉ์์ง์ ๋ํ ๋๋ผ์ด๋ฒ ๋ก๊ทธ๋ฅผ ํ์ธํ์ญ์์ค.2018-09-04 08:52:55
์ค๋ฅ AsyncE ventQueue:91 - TaskFailedListener์ ๊ฒ์ํ๋ ๋์ ์ค๋จ๋์์ต๋๋ค.
ํด๋น listener.java.lang.InterruptedException ์ ๊ฑฐ: ExecutorLost ์ค
XGBoost ๊ต์ก: ExecutorLostFailure(๋ค์ ์ค ํ๋๋ก ์ธํด ์คํ๊ธฐ 0์ด ์ข ๋ฃ๋์์ต๋๋ค.
์คํ ์ค์ธ ์์ ) ์ด์ : ์๊ฒฉ RPC ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ์ด ํด์ ๋์์ต๋๋ค. ์๋ง๋ ๋ค์์ผ๋ก ์ธํด
์๊ณ๊ฐ์ ์ด๊ณผํ๋ ์ปจํ ์ด๋ ๋๋ ๋คํธ์ํฌ ๋ฌธ์ . ๋๋ผ์ด๋ฒ ๋ก๊ทธ ํ์ธ
๊ฒฝ๊ณ ๋ฉ์์ง. ~์
org.apache.spark.TaskFailedListener.onTaskEnd(SparkParallelismTracker.scala:116)
~์
org.apache.spark.scheduler.SparkListenerBus$class.doPostEvent(SparkListenerBus.scala:45)
~์
org.apache.spark.scheduler.AsyncEventQueue.doPostEvent(AsyncEventQueue.scala:37)
~์
org.apache.spark.scheduler.AsyncEventQueue.doPostEvent(AsyncEventQueue.scala:37)
org.apache.spark.util.ListenerBus$class.postToAll(ListenerBus.scala:91)
'''โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/dmlc/xgboost/issues/1698#issuecomment-418341557 ๋๋ ์์๊ฑฐ
์ค๋ ๋
https://github.com/notifications/unsubscribe-auth/AJY-XklxsZB_FE7ZoAarV_fqw8D3JqxWks5uXmwqgaJpZM4KgAY_
.
@sagnik-rzt pyspark ๋ํผ๊ฐ XGboost 0.72๋ง ์ง์ํ๊ธฐ ๋๋ฌธ์ ์ ํ ์๋ํ์ง ์๋๋ค๋ ์ฌ์ค์ ๋๋์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ฌ์ ํ 0.8์์ ์์ ํ๊ณ ์์ต๋๋ค.
@thesuperzapper , ๊ทํ๊ฐ ์ ๊ณตํ ๋ฒ์ ์ ๊ธฐ๋ฐ์ผ๋ก xgboost 0.80์ ์ง์ํ๋๋ก ์ผ๋ถ ๋ถ๋ถ์ ๋ค์ ์์ ํ์ต๋๋ค.
๊ทธ๋ฌ๋ py4j.protocol.Py4JError: ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier does not exist in the JVM
์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ฌ๊ธฐ์ ์ ์ฒด ์ค๋ช
์ ์ ๊ณตํ์ต๋๋ค. ์ข ๋ด์ฃผ์๊ฒ ์ด์?
๋ชจ๋ ์ฝ๋๋ ์ฌ๊ธฐ ์ ๋ฐฐ์น
0.8์์ ์๋ํ๋๋ก ๋ง๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋ ๋ง์ ๋ณ๊ฒฝ ์ฌํญ์ด ํ์ํฉ๋๋ค.
๋ด๊ฐ 0.8 ๋ฒ์ ์ ๋ด๋์ง ์์ ์ฃผ๋ ์ด์ ๋ 0.72์์์ ๊ฐ์ด xgboost ํน์ ํ์ดํ๋ผ์ธ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ์ถ์ง ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ธฐ๋ณธ ํ์ดํ๋ผ์ธ ์ง์์ฑ์ ์ฌ์ฉํฉ๋๋ค.
@thesuperzapper , 0.72 ์ ๋ํ ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด์ XGBoostPipeline
๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ง ์๊ณ XGBoostEstimator
๊ฐ์ฒด๋ฅผ ์ง์ ์ฌ์ฉํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ ๊ฒ ํ๋ ๋์ ํ๋ จ/ํผํ
์ด ํด๋ฌ์คํฐ์ ์์
์์๊ฒ ๋ถ์ฐ๋์ง ์๋๋ค๋ ๊ฒ์ ์์์ต๋๋ค. ์์
์ ์ ์ฒด์ ๋ฐฐํฌํ๋ ค๋ฉด XGBoostPipeline
๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๊น?
๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ๊ต์ก์ด ์ง์๋ค์๊ฒ ๋ถ์ฐ๋์ง ์๋ ์ด์ ๋ฅผ ์๊ณ ์์ต๋๊น?
์
๋ฐ์ดํธ
XGBoostPipeline
์์ XGBoostEstimator
๋ฅผ ์คํ
์ด์ง๋ก ์ค์ ํ์ฌ ๊ต์ก์ ์๋ํ์ง๋ง ๋ฌธ์ ๊ฐ ์ง์๋ฉ๋๋ค. ๋ค๋ฅธ pyspark ์ง์ ๋ชจ๋ธ์ ๋ํด ์ํํ๋ ๋์ ํด๋ฌ์คํฐ์์ ์คํํ ๋ ๊ต์ก์ด ์์
์ ๊ฐ์ ๋ถ์ฐ๋์ง ์์ต๋๋ค.
์ด ํ๋์ ๊ด์ฐฐํ์ จ์ต๋๊น? ์ด๋ป๊ฒ ํด๊ฒฐํฉ๋๊น?
๋๋ ๋๋ถ๋ถ XGBoost 0.8์ฉ ๋ํผ๋ฅผ ๋ค์ ์ฝ๋ฉํ์ง๋ง ๋ด ์์ ํด๋ฌ์คํฐ๊ฐ ์ฌ์ ํ 2.2์ ์๊ธฐ ๋๋ฌธ์ ๋ด Dockerized Spark 2.3 ํด๋ฌ์คํฐ๊ฐ ์ ํ ์์น ๋๋ฝ ๋ฌธ์ ์์ด Scala XGBoost ๋ถ์ฐ ๋ชจ๋ธ์ ํ๋ จํ ์๋ ์๊ธฐ ๋๋ฌธ์ ๋ถ์ฐ ๋ชจ๋์์ ์ฝ๊ฒ ํ ์คํธํ ์ ์์ต๋๋ค. .
@sagnik-rzt ๋ฐ ๊ธฐํ ์ฌ์ฉ์๊ฐ ๊ฒช๊ณ ์๋ ๋ฌธ์ ๋ ํด๋ฌ์คํฐ ๊ตฌ์ฑ ๋๋ Spark-Scala XGBoost์ ๋ ๊น์ ๋ฌธ์ ์ ๊ด๋ จ์ด ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
Spark-Scala XGBoost์์ ๋ชจ๋ธ์ ํ๋ จํ ์ ์์ต๋๊น?
@thesuperzapper ๋๋ถ์ ์ ํ ์์น๊ฐ ๋ด๋ถ์ ์ผ๋ก ์ฒ๋ฆฌ๋๋ค๊ณ ์๊ฐํ์ต๋๋ค. ์ฆ, ํด๋ฌ์คํฐ ๊ตฌ์ฑ๊ณผ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ด stackoverflow ๊ฒ์๋ฌผ์ ์ฐพ์์ผ๋ฏ๋ก ์ด๋ฌํ ์ ์์ ๊ตฌํํ ๊ฒ์ ๋๋ค.
๋ํ ์ค๋น๊ฐ ๋์์ผ๋ฉด 0.8 ๋ฒ์ ์ ๊ณต์ ํ ์ ์์ต๋๊น? ๋ด ํด๋ฌ์คํฐ์์ ๋ฐฐํฌ๋ฅผ ํ ์คํธํ ์ ์์ต๋๋ค. ์คํํฌ 2.3.1๊ณผ ํ์ด์ฌ 3.5๊ฐ ์์ต๋๋ค.
๋ชจ๋ธ์ ์ ์ฅํ๊ณ ๋ก๋ํ ํ ๋ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
IllegalArgumentException: u'requirement ์คํจ: ๋ฉํ๋ฐ์ดํฐ ๋ก๋ ์ค๋ฅ: ํด๋์ค ์ด๋ฆ org.apache.spark.ml.Pipeline์ด ํ์ํ์ง๋ง ํด๋์ค ์ด๋ฆ org.apache.spark.ml.PipelineModel์ ์ฐพ์์ต๋๋ค.
์ด๊ฒ ์ข ๋์์ฃผ์ธ์. ๊ฐ์ฌ
import pyspark
from pyspark.sql.session import SparkSession
from pyspark.sql.types import *
from pyspark.ml.feature import StringIndexer, VectorAssembler
from pyspark.ml import Pipeline
from pyspark.sql.functions import col
spark.sparkContext.addPyFile("sparkxgb.zip")
from sparkxgb import XGBoostEstimator
schema = StructType(
[StructField("PassengerId", DoubleType()),
StructField("Survival", DoubleType()),
StructField("Pclass", DoubleType()),
StructField("Name", StringType()),
StructField("Sex", StringType()),
StructField("Age", DoubleType()),
StructField("SibSp", DoubleType()),
StructField("Parch", DoubleType()),
StructField("Ticket", StringType()),
StructField("Fare", DoubleType()),
StructField("Cabin", StringType()),
StructField("Embarked", StringType())
])
df_raw = spark\
.read\
.option("header", "true")\
.schema(schema)\
.csv("train.csv")
df = df_raw.na.fill(0)
sexIndexer = StringIndexer()\
.setInputCol("Sex")\
.setOutputCol("SexIndex")\
.setHandleInvalid("keep")
cabinIndexer = StringIndexer()\
.setInputCol("Cabin")\
.setOutputCol("CabinIndex")\
.setHandleInvalid("keep")
embarkedIndexer = StringIndexer()\
.setInputCol("Embarked")\
.setOutputCol("EmbarkedIndex")\
.setHandleInvalid("keep")
vectorAssembler = VectorAssembler()\
.setInputCols(["Pclass", "SexIndex", "Age", "SibSp", "Parch", "Fare", "CabinIndex", "EmbarkedIndex"])\
.setOutputCol("features")
xgboost = XGBoostEstimator(
featuresCol="features",
labelCol="Survival",
predictionCol="prediction"
)
pipeline = Pipeline().setStages([sexIndexer, cabinIndexer, embarkedIndexer, vectorAssembler, xgboost])
model = pipeline.fit(df)
model.transform(df).select(col("PassengerId"), col("prediction")).show()
model.save("model_xgboost")
loadedModel = Pipeline.load("model_xgboost")
IllegalArgumentException: u'requirement failed: Error loading metadata: Expected class name org.apache.spark.ml.Pipeline but found class name org.apache.spark.ml.PipelineModel'
#predict2 = loadedModel.transform(df)
๋ค์ ์ต์ ์ ์๋ํ์ต๋๋ค.
from pyspark.ml import PipelineModel
#model.save("model_xgboost")
loadedModel = PipelineModel.load("model_xgboost")
๋ค์ ์ค๋ฅ ๋ฐ์
ml.dmlc.xgboost4j.scala.spark๋ผ๋ ๋ชจ๋์ด ์์ต๋๋ค.
๊ฐ๋ฐ์ ๋ค์ด๋ก๋ ๋งํฌ: sparkxgb.zip
์ด ๋ฒ์ ์ XGBoost-0.8์์ ์๋ํ์ง๋ง ํ
์คํธ๋ ์ด ์ค๋ ๋์ ๊ธฐ์ฌํ๋ ๊ฒ ์ธ์๋ ์ฌ์ฉํ์ง ๋ง์ญ์์ค. ๋ณ๊ฒฝ๋ ๊ฒ์
๋๋ค.
(๋ํ ์ฐธ๊ณ : Spark 2.2์ ๋ชจ๋ ๋ฐฑํฌํธ๋ฅผ ์ ๊ฑฐํ์ผ๋ฏ๋ก Spark 2.3๋ง ์ง์ํฉ๋๋ค.)
ํด๋น ๋ฒ์ ์์ ๋ด๊ฐ ์๊ณ ์๋ ์ฃผ์ ๋ฌธ์ ๋ ๋ถ๋ฅ ๋ชจ๋ธ์ด ์ ์ฅ๋ ํ ๋ค์ ๋ก๋๋์ง ์์ TypeError: 'JavaPackage' object is not callable
์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๋ ๊ฒ์
๋๋ค. ๊ทธ๋ฌ๋ ์ด์ํ๊ฒ๋ XGBoostPipelineModel์ XGBoost ๋ถ๋ฅ ๋จ๊ณ์์ ์ ์๋ํฉ๋๋ค. ์ด๊ฒ์ ๋ด ๋ฌธ์ ๋ผ๊ณ ์๊ฐํ๊ฒ ํฉ๋๋ค. ๋๊ตฐ๊ฐ ๋ถ๋ฅ ๋ชจ๋ธ์ ์ฝ๋ ๊ฒ์ด ํจ๊ณผ๊ฐ ์๋์ง ํ์ธํ ์ ์์ต๋๊น?
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ , ์ ๋ DefaultParamsWritable ์ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํํ๋ ค๊ณ ์๋ XGBoostPipeline
๋ํ ํ์์ฑ์ ์ ๊ฑฐํ ๊ฒ์
๋๋ค. ์ด๋ ์ฅ๊ธฐ์ ์ผ๋ก ์ ์ง ๊ด๋ฆฌํ๊ธฐ๊ฐ ํจ์ฌ ์ฌ์ฐ๋ฏ๋ก ์ฝ๊ธฐ/์ฐ๊ธฐ ๋ฌธ์ ๋ ์ด์จ๋ ๊ด๋ จ์ด ์์ด์ผ ํฉ๋๋ค. (์ด๋ ๊ฒ ํ๋ฉด CrossValidator์์ ์ง์์ฑ์ด ์๋ํ ์๋ ์์ต๋๋ค.)
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
@CodingCat @tqchen ๋ฐ์ดํฐ ๊ณผํ ์ปค๋ฎค๋ํฐ๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก PySpark์์ ๊ตฌํ๋ XGboost์ ์ด์ ์ ํ์คํ ๋๋ฆด ๊ฒ์ ๋๋ค.
http://redmonk.com/sogrady/2017/03/17/language-rankings-1-17/
https://jobsquery.it/stats/language/group;
http://r4stats.com/articles/popularity/)
๋ด ๊ฒฐ๋ก : PySpark์์ ๊ตฌํ๋ XGboost๋ ๋ค๋ฅธ ๋ชจ๋ ๊ตฌํ ์ค์์ DataScience์ ๊ฐ์ฅ ํฐ ์ํฅ์ ๋ฏธ์น ๊ฒ์ ๋๋ค.
(PS๊ฐ ์ผ๋จ ์์ ๋๋ฉด Cloudera์์ ๊ตฌํํ๋์ง ํ์ธ)