变压器在pyspark.ml中的多个功能上运行

时间:2017-01-24 12:36:14

标签: apache-spark pyspark apache-spark-ml

我想在DataFrame中创建自己的功能转换器,以便添加一列,例如,其他两列之间的差异。我跟着this question,但那里的变压器仅在一列上运行。 pyspark.ml.Transformer将字符串作为inputCol的参数,因此我当然不能指定多列。

基本上,我想要实现的是_transform()方法,类似于这个方法:

def _transform(self, dataset):
    out_col = self.getOutputCol()
    in_col = dataset.select([self.getInputCol()])

    # Define transformer logic
    def f(col1, col2):
        return col1 - col2
    t = IntegerType()

    return dataset.withColumn(out_col, udf(f, t)(in_col))

这怎么可能呢?

2 个答案:

答案 0 :(得分:5)

我设法通过首先从我想要操作的功能集中创建Vector,然后在新生成的矢量要素上应用变换来解决问题。下面是一个示例代码,说明如何创建一个与其他两个功能不同的新功能:

class MeasurementDifferenceTransformer(Transformer, HasInputCol, HasOutputCol):  

    @keyword_only
    def __init__(self, inputCol=None, outputCol=None):
        super(MeasurementDifferenceTransformer, self).__init__()
        kwargs = self.__init__._input_kwargs
        self.setParams(**kwargs)

    @keyword_only
    def setParams(self, inputCol=None, outputCol=None):
        kwargs = self.setParams._input_kwargs
        return self._set(**kwargs)

    def _transform(self, dataset):
        out_col = self.getOutputCol()
        in_col = dataset[self.getInputCol()]

        # Define transformer logic
        def f(vector):
            return float(vector[0] - vector[1])
        t = FloatType()

        return dataset.withColumn(out_col, udf(lambda x: f(x), t)(in_col))

要使用它,我们首先实例化VectorAssembler以创建矢量要素:

pair_assembler = VectorAssembler(inputCols=["col1", "col2"], outputCol="cols_vector")

然后我们实例化变换器:

pair_transformer = MeasurementDifferenceTransformer(inputCol="cols_vector", outputCol="col1_minus_col2")

最后我们转换数据:

pairfeats = pair_assembler.transform(df)
difffeats = pait_transformer.transform(pairfeats)

答案 1 :(得分:2)

为了在多个列上操作,您不需要经历所有这些麻烦。这是使用HasInputCols(而不是HasInputCol)

的更好方法
class MeasurementDifferenceTransformer(Transformer, HasInputCols, HasOutputCol):  
    @keyword_only
    def __init__(self, inputCols=None, outputCol=None):
        super(MeasurementDifferenceTransformer, self).__init__()
        kwargs = self._input_kwargs
        self.setParams(**kwargs)

    @keyword_only
    def setParams(self, inputCols=None, outputCol=None):
        kwargs = self._input_kwargs
        return self._set(**kwargs)

    def _transform(self, dataset):
        out_col = self.getOutputCol()
        in_col = self.getInputCols()

        # Define transformer logic
        def f(col1, col2):
            return float(col1-col2)
        t = FloatType()

        return dataset.withColumn(out_col, udf(lambda f, t)(*in_col))