2016-11-29 7 views
2

У меня есть модель масштабирования LIBSVM (сгенерированная с помощью svm-scale), которую я хотел бы передать в PySpark. Я наивно попытался следующим:Как я могу прочитать модели LIBSVM (сохраненные с использованием LIBSVM) в PySpark?

scaler_path = "path to model" 
a = MinMaxScaler().load(scaler_path) 

Но я бросил ошибку, ожидая каталог метаданных:

Py4JJavaErrorTraceback (most recent call last) 
<ipython-input-22-1942e7522174> in <module>() 
----> 1 a = MinMaxScaler().load(scaler_path) 

/srv/data/spark/spark-2.0.0-bin-hadoop2.6/python/pyspark/ml/util.pyc in load(cls, path) 
    226  def load(cls, path): 
    227   """Reads an ML instance from the input path, a shortcut of `read().load(path)`.""" 
--> 228   return cls.read().load(path) 
    229 
    230 

/srv/data/spark/spark-2.0.0-bin-hadoop2.6/python/pyspark/ml/util.pyc in load(self, path) 
    174   if not isinstance(path, basestring): 
    175    raise TypeError("path should be a basestring, got type %s" % type(path)) 
--> 176   java_obj = self._jread.load(path) 
    177   if not hasattr(self._clazz, "_from_java"): 
    178    raise NotImplementedError("This Java ML type cannot be loaded into Python currently: %r" 

/usr/local/lib/python2.7/dist-packages/py4j/java_gateway.pyc in __call__(self, *args) 
    1131   answer = self.gateway_client.send_command(command) 
    1132   return_value = get_return_value(
-> 1133    answer, self.gateway_client, self.target_id, self.name) 
    1134 
    1135   for temp_arg in temp_args: 

/srv/data/spark/spark-2.0.0-bin-hadoop2.6/python/pyspark/sql/utils.pyc in deco(*a, **kw) 
    61  def deco(*a, **kw): 
    62   try: 
---> 63    return f(*a, **kw) 
    64   except py4j.protocol.Py4JJavaError as e: 
    65    s = e.java_exception.toString() 

/usr/local/lib/python2.7/dist-packages/py4j/protocol.pyc in get_return_value(answer, gateway_client, target_id, name) 
    317     raise Py4JJavaError(
    318      "An error occurred while calling {0}{1}{2}.\n". 
--> 319      format(target_id, ".", name), value) 
    320    else: 
    321     raise Py4JError(

Py4JJavaError: An error occurred while calling o321.load. 
: org.apache.hadoop.mapred.InvalidInputException: Input path does not exist: file:[filename]/metadata 

`` `

есть простая работа вокруг Загрузите это? Формат модели LIBSVM:

x 
0 1 
1 -1050 1030 
2 0 1 
3 0 3 
4 0 1 
5 0 1 

ответ

5

Во-первых, файл представлен не в формате libsvm. Правильный формат файла libsvm следующий:

<label> <index1>:<value1> <index2>:<value2> ... <indexN>:<valueN> 

Таким образом, для вашей подготовки данных для начала неправильной подготовки.

Во-вторых, метод класса load(path), который вы используете с MinMaxScaler, считывает экземпляр ML из входного пути.

Помните, что:MinMaxScaler вычисляет суммарную статистику по набору данных и производит MinMaxScalerModel. Затем модель может преобразовать каждую функцию отдельно, чтобы она находилась в заданном диапазоне.

например:

from pyspark.ml.linalg import Vectors 
from pyspark.mllib.regression import LabeledPoint 
from pyspark.ml.feature import MinMaxScaler 
df = spark.createDataFrame([(1.1, Vectors.sparse(3, [(0, 1.23), (2, 4.56)])) ,(0.0, Vectors.dense([1.01, 2.02, 3.03]))],['label','features']) 

df.show(truncate=False) 
# +-----+---------------------+ 
# |label|features    | 
# +-----+---------------------+ 
# |1.1 |(3,[0,2],[1.23,4.56])| 
# |0.0 |[1.01,2.02,3.03]  | 
# +-----+---------------------+ 

mmScaler = MinMaxScaler(inputCol="features", outputCol="scaled") 
temp_path = "/tmp/spark/" 
minMaxScalerPath = temp_path + "min-max-scaler" 
mmScaler.save(minMaxScalerPath) 

Фрагмент выше сохранит трансформатор на MinMaxScaler функции, поэтому он может быть загружен после того, как с нагрузкой методы класса.

Теперь давайте посмотрим, что на самом деле произошло. Метод класса save создаст следующую структуру файла:

/tmp/spark/ 
└── min-max-scaler 
    └── metadata 
     ├── part-00000 
     └── _SUCCESS 

Давайте проверять содержимое этого part-0000 файла:

$ cat /tmp/spark/min-max-scaler/metadata/part-00000 | python -m json.tool 
{ 
    "class": "org.apache.spark.ml.feature.MinMaxScaler", 
    "paramMap": { 
     "inputCol": "features", 
     "max": 1.0, 
     "min": 0.0, 
     "outputCol": "scaled" 
    }, 
    "sparkVersion": "2.0.0", 
    "timestamp": 1480501003244, 
    "uid": "MinMaxScaler_42e68455a929c67ba66f" 
} 

Так на самом деле при загрузке трансформатора:

loadedMMScaler = MinMaxScaler.load(minMaxScalerPath) 

You фактически загружают этот файл. Это не будет файл libsvm!

Теперь вы можете применить трансформатор для создания модели и превратить ваш DataFrame:

model = loadedMMScaler.fit(df) 

model.transform(df).show(truncate=False)          
# +-----+---------------------+-------------+ 
# |label|features    |scaled  | 
# +-----+---------------------+-------------+ 
# |1.1 |(3,[0,2],[1.23,4.56])|[1.0,0.0,1.0]| 
# |0.0 |[1.01,2.02,3.03]  |[0.0,1.0,0.0]| 
# +-----+---------------------+-------------+ 

Теперь давайте вернемся к этому libsvm файл и давайте создадим несколько фиктивных данных и сохранить его в формате libsvm с помощью MLUtils

from pyspark.mllib.regression import LabeledPoint 
from pyspark.mllib.linalg import Vectors 
from pyspark.mllib.util import MLUtils 
data = sc.parallelize([LabeledPoint(1.1, Vectors.sparse(3, [(0, 1.23), (2, 4.56)])), LabeledPoint(0.0, Vectors.dense([1.01, 2.02, 3.03]))]) 
MLUtils.saveAsLibSVMFile(data, temp_path + "data") 

Вернуться к нашей структуре файла:

/tmp/spark/ 
├── data 
│   ├── part-00000 
│   ├── part-00001 
│   ├── part-00002 
│   ├── part-00003 
│   ├── part-00004 
│   ├── part-00005 
│   ├── part-00006 
│   ├── part-00007 
│   └── _SUCCESS 
└── min-max-scaler 
    └── metadata 
     ├── part-00000 
     └── _SUCCESS 

Вы можете проверить содержимое этих файлов, который находится в формате libsvm сейчас:

$ cat /tmp/spark/data/part-0000* 
1.1 1:1.23 3:4.56 
0.0 1:1.01 2:2.02 3:3.03 

Теперь загрузить данные и применять:

loadedData = MLUtils.loadLibSVMFile(sc, temp_path + "data") 
loadedDataDF = spark.createDataFrame(loadedData.map(lambda lp : (lp.label, lp.features.asML())), ['label','features']) 

loadedDataDF.show(truncate=False) 
# +-----+----------------------------+            
# |label|features     | 
# +-----+----------------------------+ 
# |1.1 |(3,[0,2],[1.23,4.56])  | 
# |0.0 |(3,[0,1,2],[1.01,2.02,3.03])| 
# +-----+----------------------------+ 

Примечание, что преобразование MLlib Vectors ОД Vectors очень важно. Вы можете узнать больше об этом here.

model.transform(loadedDataDF).show(truncate=False) 
# +-----+----------------------------+-------------+ 
# |label|features     |scaled  | 
# +-----+----------------------------+-------------+ 
# |1.1 |(3,[0,2],[1.23,4.56])  |[1.0,0.0,1.0]| 
# |0.0 |(3,[0,1,2],[1.01,2.02,3.03])|[0.0,1.0,0.0]| 
# +-----+----------------------------+-------------+ 

Я надеюсь, что это ответит на ваш вопрос!