def getPrediction(textInput, k):
    text_list = textInput.split(' ')
    data = []
    for word in text_list:
        data.append((regex.sub(' ', word).lower(), 1))
    wordsInThatDoc = sqlContext.createDataFrame(data, ["word", "count"])
    allDictionaryWordsInThatDoc = dictionary.join(
        wordsInThatDoc, wordsInThatDoc.word == dictionary.words, 'inner')
    myArray_idf = allDictionaryWordsInThatDoc.groupBy(wordsInThatDoc.word).agg(
        sum_("count").alias("count"),
        buildArray_udf(func.collect_list("position")).alias("idf")).orderBy(
            "count", ascending=False).limit(1).select('idf')
    myArray = np.multiply(myArray_idf.select('idf').collect(), idfArray)
    distance_udf = udf(lambda x: float(np.dot(np.array(x), myArray[0][0])),
                       FloatType())
    distances = features.withColumn('distance', distance_udf('position_array'))
    topK = distances.orderBy('distance', ascending=False).limit(k)
    docIDRepresented = topK.withColumn('cnt', lit(1)).drop('tfidf')
    numTimes = docIDRepresented.groupBy("Category").agg(
        sum_("cnt").alias("count")).drop("cnt")
    numTimes_order = numTimes.orderBy('count', ascending=False).limit(k)
    return numTimes_order.collect()
예제 #2
0
    def _transform_data(self, df, df_base):
        """Transform original dataset.

        :param df: Input DataFrame.
        :return: Transformed DataFrame.
        """
        if self._is_diario:
            df = df.withColumn('TEST', lit(1))
            df_base = df_base.withColumn('TEST', lit(0))
            df = df.union(df_base)
            del df_base

        # Cast key variables and rename headers
        df = df.withColumnRenamed('auditCodigoSiniestroReferencia',
                                  'id_siniestro')
        df = df.withColumn('id_siniestro',
                           df['id_siniestro'].cast(IntegerType()))
        df = df.dropna(subset=['id_siniestro'])
        df = df.withColumnRenamed('auditFechaAperturaSiniestroReferencia',
                                  'fecha_apertura_siniestro')

        # VARIABLES DE FECHA: We convert every date variable to a same format and we control the date
        variable_fecha = [
            "hist_poliza_fecha_inicio", "hist_poliza_fecha_efecto_natural",
            "hist_poliza_fecha_efecto_mvto", "hist_poliza_fecha_vto_mvto",
            "hist_poliza_vto_natural"
        ]

        for col in variable_fecha:
            df = df.withColumn(
                col,
                when(df[col] == '1900-01-01', None).otherwise(df[col]))

        control_fecha = [
            "hist_poliza_fecha_inicio", "hist_poliza_fecha_efecto_natural"
        ]
        func = udf(lambda x: datetime.datetime.strptime(x, '%Y/%m/%d'),
                   DateType())
        for col in control_fecha:
            df = df.dropna(subset=[col])
            df = df.filter(df[col] <= STRING.DAY)
            df = df.filter(
                df[col] > (datetime.datetime.today() +
                           relativedelta(years=-5)).strftime('%Y-%m-%d'))
        for col in variable_fecha:
            df = df.withColumn(col, func(df[col]))

        df = df.orderBy(['id_siniestro'], ascending=[True])

        # COUNT POLIZAS POR SINIESTRO: We weight the policies by sinister
        df = df.withColumn('pondera_poliza', lit(1))
        w = (Window().partitionBy(df.id_siniestro).rowsBetween(
            -sys.maxsize, sys.maxsize))
        df = df.withColumn('hist_mov_poliza_otro_count',
                           sum_(df['pondera_poliza']).over(w))

        # POR PRODUCTO: We use an extra table to group the products
        types = df.select('hist_id_producto').distinct().collect()
        types = [ty['hist_id_producto'] for ty in types]
        types_list = [
            when(df['hist_id_producto'] == ty,
                 1).otherwise(0).alias('d_d_hist_mov_poliza_otro_producto_' +
                                       ty) for ty in types
        ]
        df = df.select(list(df.columns) + types_list)
        df.drop('hist_id_producto')

        # PROMEDIO DE VERSIONES: We count the versions by policy and then we get the average by policy.
        df = df.withColumn(
            'hist_mov_poliza_otro_version_count',
            sum_(df['hist_poliza_version'].cast(IntegerType())).over(w))
        df = df.withColumn(
            'hist_mov_poliza_otro_version_promedioxpoliza',
            df['hist_mov_poliza_otro_version_count'] /
            df['hist_mov_poliza_otro_count'])

        # PROMEDIO DE SUPLEMENTOS: We count the suplements by policy and then we get the average by policy.
        df = df.withColumn(
            'hist_mov_poliza_otro_suplemento_count',
            sum_(df['hist_poliza_suplementos'].cast(IntegerType())).over(w))
        df = df.withColumn(
            'hist_mov_poliza_otro_suplemento_promedioxpoliza',
            df['hist_mov_poliza_otro_suplemento_count'] /
            df['hist_mov_poliza_otro_count'])

        # ULTIMO MOVIMIENTO: We group the policy last movement by ANULACION, CARTERA, REGULARIZACION or SUPLMENTO
        dict_replace = {
            'ANULACION': 'ANULACION',
            'CARTERA': 'CARTERA',
            'REGULARIZACION': 'REGULARIZACION',
            'SUPLEMENTO': 'SUPLEMENTO'
        }
        func = udf(
            lambda x: f.replace_dict_starswith(x, key_values=dict_replace),
            StringType())
        df = df.withColumn('hist_poliz_ultimo_movimiento',
                           func(df['hist_poliz_ultimo_movimiento']))

        # VARIABLES CATEGÓRICAS: We get dummies from categorical variables
        variable_categorica = [
            "hist_poliz_ultimo_movimiento", "hist_poliza_estado"
        ]
        variable_dummy = []
        for col in variable_categorica:
            types = df.select(col).distinct().collect()
            types = [ty[col] for ty in types]
            types_list = [
                when(df[col] == ty,
                     1).otherwise(0).alias('d_' + col + '_' + ty)
                for ty in types if ty is not None
            ]
            variable_dummy += [
                'd_' + col + '_' + ty for ty in types if ty is not None
            ]
            df = df.select(list(df.columns) + types_list)

        variable_dummy += ['hist_poliza_sospechoso']
        for col in variable_dummy:
            name = col + '_count'
            df = df.fillna({col: 0})
            df = df.withColumn(name, sum_(df[col].cast(IntegerType())).over(w))

        # FECHAS
        # 1) Inicio-Efecto:
        # Efecto Natural de la Póliza - Fecha Inicio Póliza
        df = df.withColumn(
            'hist_mov_poliza_otro_dif_inicio_efecto',
            datediff('hist_poliza_fecha_efecto_natural',
                     'hist_poliza_fecha_inicio'))
        df = df.withColumn(
            'hist_mov_poliza_otro_dif_inicio_efecto_negativo',
            when(df['hist_mov_poliza_otro_dif_inicio_efecto'] < 0,
                 1).otherwise(0))
        df = df.withColumn(
            'hist_mov_poliza_otro_dif_inicio_efecto_negativo',
            sum_(
                df['hist_mov_poliza_otro_dif_inicio_efecto_negativo']).over(w))

        # Acumulamos la diferencia efecto-inicio, sacamos el promedio por siniestro de la póliza
        df = df.withColumn(
            'hist_mov_poliza_otro_dif_inicio_efecto_sum',
            sum_(df['hist_mov_poliza_otro_dif_inicio_efecto']).over(w))
        df = df.withColumn(
            'hist_mov_poliza_otro_dif_inicio_efecto_promedio',
            df['hist_mov_poliza_otro_dif_inicio_efecto_sum'] /
            df['hist_mov_poliza_otro_count'])

        # 2) Efecto- Efecto vto.
        # Vencimiento Natural - Efecto Natural de la Póliza
        df = df.withColumn(
            'hist_mov_poliza_otro_dif_efecto_vto',
            datediff('hist_poliza_vto_natural',
                     'hist_poliza_fecha_efecto_natural'))

        # Acumulamos vto-efecto y obtenemos el promedio por siniestro de la póliza
        df = df.withColumn(
            'hist_mov_poliza_otro_dif_efecto_vto_promedio',
            sum_(df['hist_mov_poliza_otro_dif_efecto_vto']).over(w))
        df = df.withColumn(
            'hist_mov_poliza_otro_dif_efecto_vto_promedio',
            df['hist_mov_poliza_otro_dif_efecto_vto_promedio'] /
            df['hist_mov_poliza_otro_count'])

        # VARIABLES INT: For the INT variables we acumulate and obtain the average by sinister.
        variables_int = ["hist_poliza_numero_siniestros"]
        for col in variables_int:
            count = col + '_count'
            promedio = col + '_promedio'
            df = df.withColumn(count,
                               sum_(df[col].cast(IntegerType())).over(w))
            df = df.withColumn(promedio,
                               df[count] / df['hist_mov_poliza_otro_count'])

        # CARGA SINIESTRAL
        df = df.withColumnRenamed('coste_del_siniestro_por_rol',
                                  'hist_poliza_carga_siniestral')
        df = df.fillna({'hist_poliza_carga_siniestral': 0})
        df = df.withColumn(
            'hist_poliza_carga_siniestral',
            df['hist_poliza_carga_siniestral'].cast(FloatType()))

        # VARIABLES FLOAT:
        variables_float = [
            "hist_poliza_carga_siniestral", "hist_poliza_recibos_pagos_importe"
        ]
        # First, before group we calculate outliers. We do it before because we want to count the outliers sinister
        # by sinister. If we first group, we lost the intra-effect of the sinister
        for col in variables_float:
            df = df.withColumn(col, df[col].cast(FloatType()))
            df = outliers.Outliers.outliers_mad(df, col, not_count_zero=True)
            count = col + '_count'
            promedio = col + '_promedio'
            name_outlier = str(col) + '_mad_outlier'
            count_outlier = name_outlier + '_count'
            promedio_outlier = name_outlier + '_promedio'
            df = df.withColumn(count_outlier, sum_(df[name_outlier]).over(w))
            df = df.withColumn(
                promedio_outlier,
                df[count_outlier] / df['hist_mov_poliza_otro_count'])
            df = df.drop(name_outlier)
            df = df.withColumn(count, sum_(df[col]).over(w))
            df = df.withColumn(promedio,
                               df[count] / df['hist_mov_poliza_otro_count'])

        df = df.dropDuplicates(subset=['id_siniestro'])

        # VARIABLES DEL
        variable_del = [
            'id_fiscal', 'id_poliza', 'hist_id_producto',
            'hist_poliza_version', 'hist_poliza_suplementos',
            'hist_poliz_ultimo_movimiento',
            'hist_poliz_motivo_ultimo_movimiento', 'hist_poliza_estado',
            'hist_poliza_fecha_inicio', 'hist_poliza_fecha_efecto_natural',
            'hist_poliza_fecha_efecto_mvto', 'hist_poliza_fecha_vto_mvto',
            'hist_poliza_vto_natural', 'hist_poliza_numero_siniestros',
            'hist_poliza_carga_siniestral',
            'hist_poliza_recibos_pagos_importe', 'fecha_apertura_siniestro',
            'pondera_poliza', 'Agrupación productos', 'Producto',
            'hist_mov_poliza_otro_dif_inicio_efecto',
            'hist_mov_poliza_otro_dif_efecto_vto', 'cliente_codfiliacion'
        ]

        df = df.drop(*variable_del)

        if self._is_diario:
            df = df.filter(df['TEST'] == 1)
            df = df.drop('TEST')

        return df
    def _transform_data(self, df, df_base, bl_processed):
        """Transform original dataset.

        :param df: Input DataFrame.
        :param bl_processed
        :return: Transformed DataFrame.
        """

        if self._is_diario:
            df = df.withColumn('TEST', lit(1))
            df_base = df_base.withColumn('TEST', lit(0))
            df = df.union(df_base)

        # Cast key variables and rename headers
        exprs = [
            df[column].alias(column.replace('"', '')) for column in df.columns
        ]
        df = df.select(*exprs)
        exprs = [
            df[column].alias(column.replace(' ', '')) for column in df.columns
        ]
        df = df.select(*exprs)

        df = df.withColumnRenamed('hist_siniestro_poliza_otro_id_siniestro',
                                  'id_siniestro')
        df = df.withColumnRenamed('auditCodigoSiniestroReferencia',
                                  'id_siniestro_ref')
        df = df.withColumn('id_siniestro_ref',
                           df.id_siniestro_ref.cast(IntegerType()))
        df = df.withColumn('id_siniestro', df.id_siniestro.cast(IntegerType()))
        df = df.dropna(subset=['id_siniestro_ref'])
        df = df.dropna(subset=['id_siniestro'])

        # DATE VARIABLES FORMAT
        fecha_variables = [
            "hist_siniestro_poliza_otro_fecha_ocurrencia",
            "hist_siniestro_poliza_otro_fecha_terminado",
            "auditFechaAperturaSiniestroReferencia"
        ]
        func = udf(lambda x: datetime.datetime.strptime(x, '%Y/%m/%d'),
                   DateType())
        for col in fecha_variables:
            df = df.fillna({col: '1900/01/01'})
            df = df.withColumn(col, func(df[col]))
            df = df.withColumn(
                col,
                when(df[col] == '1900-01-01', None).otherwise(df[col]))
            df = df.filter(df[col] <= time.strftime('%Y-%m-%d'))

        # We check that the sinister in the other policy is before the reference sinister, because we want to know the
        # past values
        df = df.filter(df['auditFechaAperturaSiniestroReferencia'] >=
                       df['hist_siniestro_poliza_otro_fecha_ocurrencia'])

        # COUNT POLIZA-VERSION: We count how many sinisters before have the costumer. It counts how many times appear a
        # row in the table, because each line is referred to a unique sinister
        df = df.withColumn('hist_sin_poliza_otro_count_version', lit(1))
        w = (Window().partitionBy(df.id_siniestro_ref).rowsBetween(
            -sys.maxsize, sys.maxsize))
        df = df.withColumn(
            'hist_sin_poliza_otro_count',
            count_(df.hist_sin_poliza_otro_count_version).over(w))

        # COUNT POLIZAS: We count how many policies has the customer. We have to construct another table so we can
        # group at the level of policies.
        count_poliza = df.select(
            ['id_siniestro_ref', 'hist_siniestro_poliza_otro_id_poliza'])
        count_poliza = count_poliza.dropDuplicates()
        count_poliza = count_poliza.withColumnRenamed(
            'hist_siniestro_poliza_otro_id_poliza',
            'hist_sin_poliza_otro_count_polizas')
        count_poliza = count_poliza.withColumn(
            'hist_sin_poliza_otro_count_polizas',
            count_(df['id_siniestro_ref']).over(w))
        count_poliza = count_poliza.dropDuplicates(subset=['id_siniestro_ref'])
        df = df.join(count_poliza, on='id_siniestro_ref', how='left')

        # SINIESTROS/POLIZAS: Here we calculate the ratio nºsinisters/nº policies
        df = df.withColumn(
            'hist_siniestro_poliza_otro_siniestros_polizas',
            df['hist_sin_poliza_otro_count'] /
            df['hist_sin_poliza_otro_count_polizas'])

        # FUE UN SINIESTRO FRAUDULENTO? We check if the id_siniestro is associated with a previous Fraud Sinister
        bl_processed = bl_processed.select('id_siniestro').dropDuplicates(
            subset=['id_siniestro'])
        bl_processed = bl_processed.withColumn('hist_sin_poliza_otro_fraude',
                                               lit(1))
        df = df.join(bl_processed, on='id_siniestro', how='left')
        df = df.withColumn(
            'hist_sin_poliza_otro_fraude',
            when(df['hist_sin_poliza_otro_fraude'].isNull(),
                 0).otherwise(df['hist_sin_poliza_otro_fraude']))

        # POR PRODUCTO: We group the product number by predefined categories in tabla_productos. It permits a better
        # classification. Here we have to pre-process the product label format to have coincidence.
        types = df.select(
            'hist_siniestro_poliza_otro_id_producto').distinct().collect()
        types = [ty['hist_siniestro_poliza_otro_id_producto'] for ty in types]
        types_list = [
            when(df['hist_siniestro_poliza_otro_id_producto'] == ty,
                 1).otherwise(0).alias('d_hist_sin_poliza_otro_producto_' + ty)
            for ty in types
        ]
        df = df.select(list(df.columns) + types_list)
        df.drop('hist_siniestro_poliza_otro_id_producto')

        # DUMMIES: We acumulate the dummy variables to get the variables at cod_filiacion level
        types = ['d_hist_sin_poliza_otro_producto_' + x for x in types]
        var_dummies = [
            "hist_siniestro_poliza_otro_bbdd",
            "hist_siniestro_poliza_otro_unidad_investigacion",
            "hist_siniestro_poliza_otro_incidencia_tecnica",
            "hist_siniestro_poliza_otro_incidencia_tecnica_positiva",
            "hist_siniestro_poliza_otro_incidencias",
            "hist_siniestro_poliza_otro_cobertura"
        ] + types
        for col in var_dummies:
            df = df.withColumn(col + '_count', sum_(df[col]).over(w))
            df = df.drop(col)

        # FECHAS: We have two dates. fecha_ocurrencia and fecha_terminado. We have to take into account claims
        # that are not finished. If the claim is notfinished we input today as date
        # and create a variable that indicates the situation.
        df = df.withColumn(
            'hist_siniestro_poliza_otro_no_terminado',
            when(df['hist_siniestro_poliza_otro_fecha_terminado'].isNull(),
                 1).otherwise(0))
        df = df.fillna({
            'hist_siniestro_poliza_otro_fecha_terminado':
            time.strftime('%Y-%m-%d')
        })

        # Claim duration: We calculate the cumulated duration and the average duration.
        df = df.withColumn(
            'hist_poliza_otro_fecha_apertura_terminado',
            datediff('hist_siniestro_poliza_otro_fecha_terminado',
                     'hist_siniestro_poliza_otro_fecha_ocurrencia'))
        df = df.withColumn(
            'hist_poliza_otro_fecha_apertura_terminado',
            sum_(df['hist_poliza_otro_fecha_apertura_terminado']).over(w))
        df = df.withColumn(
            'hist_poliza_otro_duracion_promedio_sin',
            df['hist_poliza_otro_fecha_apertura_terminado'] /
            df['hist_sin_poliza_otro_count'])

        # ULTIMO SINIESTRO DE LA POLIZA
        df = df.withColumnRenamed(
            'hist_siniestro_poliza_otro_fecha_ocurrencia',
            'hist_siniestro_poliza_otro_ultimo_fecha_ocurrencia')
        df = df.orderBy('hist_siniestro_poliza_otro_ultimo_fecha_ocurrencia',
                        ascending=False)

        # CARGA SINIESTRAL
        # Outlier: First we calculate the outliers quantity by cliente-sinister so we can get the intra-effect
        df = df.withColumnRenamed(
            'coste_del_siniestro_por_rol',
            'hist_siniestro_poliza_otro_carga_siniestral')
        df = df.fillna({'hist_siniestro_poliza_otro_carga_siniestral': 0})
        df = df.withColumn(
            'hist_siniestro_poliza_otro_carga_siniestral',
            df.hist_siniestro_poliza_otro_carga_siniestral.cast(FloatType()))

        # Construimos el outlier a nivel siniestro: Luego hacemos la suma de los casos de outlier por id_siniestro_ref
        df = outliers.Outliers.outliers_mad(
            df,
            'hist_siniestro_poliza_otro_carga_siniestral',
            not_count_zero=True)
        df = df.withColumn(
            'hist_siniestro_poliza_otro_carga_siniestral_mad_outlier_count',
            sum_(df['hist_siniestro_poliza_otro_carga_siniestral_mad_outlier']
                 ).over(w))
        df = df.withColumn(
            'hist_siniestro_poliza_otro_carga_siniestral_mad_outlier_promedio',
            df['hist_siniestro_poliza_otro_carga_siniestral_mad_outlier_count']
            / df['hist_sin_poliza_otro_count'])
        df = df.drop('hist_siniestro_poliza_otro_carga_siniestral_mad_outlier')

        # We calculate the sum and the average by sinister
        df = df.withColumn(
            'hist_siniestro_poliza_otro_carga_siniestral_count',
            sum_(df['hist_siniestro_poliza_otro_carga_siniestral']).over(w))
        df = df.withColumn(
            'hist_siniestro_poliza_otro_carga_siniestral_promedio',
            df['hist_siniestro_poliza_otro_carga_siniestral_count'] /
            df['hist_sin_poliza_otro_count'])

        # COBERTURAS
        # mayor a 3: we consider as outlier > 3, because the mean is concentrated around 1.28
        df = df.withColumn(
            'hist_sin_poliza_otro_mayor3coberturas',
            when(df["hist_siniestro_poliza_otro_coberturas_involucradas"] > 3,
                 1).otherwise(0))
        df = df.withColumn(
            'hist_sin_poliza_otro_mayor3coberturas',
            sum_(df['hist_sin_poliza_otro_mayor3coberturas']).over(w))

        # promedio: Average by claim
        df = df.withColumn(
            'hist_sin_poliza_otro_cober_sum',
            sum_(
                df['hist_siniestro_poliza_otro_coberturas_involucradas']).over(
                    w))
        df = df.withColumn(
            'hist_sin_poliza_otro_cober_promedio',
            df["hist_sin_poliza_otro_cober_sum"] /
            df['hist_sin_poliza_otro_count'])

        # pagas-cubiertas: We calculate this at the coustomer cumulated level and not to claim level
        df = df.withColumn(
            'hist_siniestro_poliza_otro_coberturas_involucradas_pagadas_sum',
            sum_(df[
                'hist_siniestro_poliza_otro_coberturas_involucradas_pagadas']).
            over(w))
        df = df.withColumn(
            'hist_sin_poliza_otro_pagas_cubiertas',
            df["hist_siniestro_poliza_otro_coberturas_involucradas_pagadas_sum"]
            / df['hist_sin_poliza_otro_cober_sum'])

        # no pagas: Here we calculate at the claim level, counting the total unpaid coverages
        df = df.withColumn(
            'hist_sin_poliza_otro_cob_no_pagas',
            when(
                df['hist_siniestro_poliza_otro_coberturas_involucradas_pagadas']
                == 0, 1).otherwise(0))
        df = df.withColumn(
            'hist_sin_poliza_otro_cob_no_pagas',
            sum_(df['hist_sin_poliza_otro_cob_no_pagas']).over(w))

        # DELETE VARIABLES: We delete variables that are not relevant or have been transformed
        del_variables = [
            'hist_siniestro_poliza_otro_id_poliza',
            'hist_siniestro_poliza_otro_id_producto',
            'hist_siniestro_poliza_otro_version',
            'hist_siniestro_poliza_otro_id_siniestro',
            'hist_siniestro_poliza_otro_fecha_terminado',
            'hist_siniestro_poliza_otro_bbdd',
            'hist_siniestro_poliza_otro_unidad_investigacion',
            'hist_siniestro_poliza_otro_incidencia_tecnica',
            'hist_siniestro_poliza_otro_incidencia_tecnica_positiva',
            'hist_siniestro_poliza_otro_incidencias',
            'hist_siniestro_poliza_otro_cobertura',
            'hist_siniestro_poliza_otro_carga_siniestral',
            'hist_siniestro_poliza_otro_coberturas_involucradas',
            'hist_siniestro_poliza_otro_coberturas_involucradas_pagadas',
            'id_fiscal', 'hist_sin_poliza_otro_count_version',
            'Agrupación productos', 'Producto',
            'auditFechaAperturaSiniestroReferencia', 'cliente_codfiliacion',
            'audit_siniestro_codigo_compania', 'id_siniestro'
        ]

        df = df.drop(*del_variables)
        df = df.withColumnRenamed('id_siniestro_ref', 'id_siniestro')
        df = df.dropDuplicates(subset=['id_siniestro'])

        # OUTLIER: We calculate the outliers referred to the ratio claims/policies.
        df = outliers.Outliers.outliers_mad(
            df,
            'hist_siniestro_poliza_otro_siniestros_polizas',
            not_count_zero=False)

        if self._is_diario:
            df = df.filter(df['TEST'] == 1)
            df = df.drop('TEST')

        return df
예제 #4
0
    def _transform(self, df, auxiliar_train):

        if not self.train_file:
            auxiliar_train = auxiliar_train.drop('WinningBid')
            auxiliar_train = auxiliar_train.withColumn('test', lit(0))
            df = df.withColumn('test', lit(1))
            df = auxiliar_train.union(df)
            del auxiliar_train

        # We create the time as Index
        split_col = split(df['ApproximateDate'], ' ')
        df = df.withColumn('time', split_col.getItem(1))  # time

        # Hour Index
        func_index = udf(lambda x: auxiliar_func.time_to_num(x, index='hms'),
                         IntegerType())
        df = df.withColumn('hms_index', func_index(df['time']))

        # We order by UserId-Date
        df = df.orderBy(['UserID', 'hms_index'])

        # We check Null Values
        df.select([count_(when(isnan(c), c)).alias(c)
                   for c in df.columns]).show()

        # We create a rank of users by how many times in the past saw an ad
        w = (Window().partitionBy(df.UserID).orderBy('time').rowsBetween(
            Window.unboundedPreceding, 0))
        df = df.withColumn('user_id_acumulative', count_(df['UserId']).over(w))

        # Number of Ads/User/Second
        df = df.withColumn('key_id',
                           concat(df['UserID'], lit(' '), df['hms_index']))
        w = (Window().partitionBy(df.key_id).orderBy('hms_index').rowsBetween(
            -sys.maxsize, sys.maxsize))
        df = df.withColumn('number_ads_user_second', count_(df.key_id).over(w))

        # Number of Ads/User
        df_group = df.groupby(['key_id'
                               ]).agg(count_('key_id').alias('count_ads'))
        split_col = split(df_group['key_id'], ' ')
        df_group = df_group.withColumn('UserID', split_col.getItem(0))  # time
        w = (Window().partitionBy(
            df_group.UserID).orderBy('key_id').rowsBetween(
                Window.unboundedPreceding, 0))
        df_group = df_group.withColumn('number_ads_user',
                                       sum_(df_group.count_ads).over(w))
        df_group = df_group.select(['key_id', 'number_ads_user'])
        df = df.join(df_group, how='left', on='key_id')
        del df_group

        # Number of Users/Second
        w = (Window().partitionBy(df.ApproximateDate).rowsBetween(
            -sys.maxsize, sys.maxsize))
        df = df.withColumn('number_user_second',
                           approx_count_distinct(df.UserID).over(w))

        # Number of Ads/Second
        df = df.withColumn('number_ads_second',
                           count_(df.ApproximateDate).over(w))

        # Browser Dummy Transformation
        types = df.select('Browser').distinct().collect()
        types = [val['Browser'] for val in types]
        new_cols = [
            when(df['Browser'] == ty, 1).otherwise(0).alias('d_browser_' + ty)
            for ty in types
        ]
        df = df.select(df.columns + new_cols)

        # Decompose Date Variables
        df = df.withColumn('date', to_date(df['ApproximateDate']))  # date
        df = df.withColumn('month', month(df['ApproximateDate']))  # month
        df = df.withColumn('day', dayofmonth(df['ApproximateDate']))  # day
        df = df.withColumn('weekday', dayofweek(
            df['ApproximateDate']))  # weekday 1=Monday

        df = df.withColumn('hour', hour(df['time']))  # hour
        df = df.withColumn('minute', minute(df['time']))  # minute

        # Peak Hour
        df = df.withColumn('peak6am8am',
                           when(df['hour'].between(6, 8), 1).otherwise(0))
        df = df.withColumn('peak14pm16pm',
                           when(df['hour'].between(14, 16), 1).otherwise(0))

        # Minute Index
        func_index = udf(lambda x: auxiliar_func.time_to_num(x, index='hm'),
                         IntegerType())
        df = df.withColumn('hm_index', func_index(df['time']))

        # Convert to time-series by Minute
        # We reduce to minutes
        df_time_serie_ads = df.select([
            'hms_index', 'hm_index', 'number_user_second', 'number_ads_second'
        ]).drop_duplicates()
        df_time_serie_user = df.select(['UserID',
                                        'hm_index']).drop_duplicates()

        # Group-by the values
        df_time_serie_user = df_time_serie_user.groupBy('hm_index').agg(
            approx_count_distinct('UserID'))
        df_time_serie_ads = df_time_serie_ads.groupBy('hm_index').agg({
            'number_ads_second':
            'sum'
        }).drop_duplicates(subset=['hm_index'])

        # Join ads-users per minute
        df_time_serie = df_time_serie_ads.join(df_time_serie_user,
                                               how='left',
                                               on='hm_index')
        del df_time_serie_ads, df_time_serie_user

        # Rename columns
        df_time_serie = df_time_serie.withColumnRenamed(
            'sum(number_ads_second)', 'number_ads_minute').withColumnRenamed(
                'approx_count_distinct(UserID)', 'number_user_minute')

        # Resample Range of Minutes
        resample_range = list(
            range(
                df_time_serie.select(min_(
                    col('hm_index'))).limit(1).collect()[0][0],
                df_time_serie.select(max_(
                    col('hm_index'))).limit(1).collect()[0][0] + 1, 1))

        resample_range = self._spark.createDataFrame(resample_range,
                                                     IntegerType())

        # Join the original df
        df_time_serie = resample_range.join(
            df_time_serie,
            how='left',
            on=resample_range.value == df_time_serie.hm_index).drop(
                *['hm_index']).fillna(0)

        # Create Lags By Minutes
        w = Window().partitionBy().orderBy(col('value'))
        if self.ar_min_lag > 0:
            df_time_serie = df_time_serie.select(
                '*',
                lag('number_user_minute').over(w).alias(
                    'ar1_number_user_minute'))
            df_time_serie = df_time_serie.select(
                '*',
                lag('number_ads_minute').over(w).alias(
                    'ar1_number_ads_minute'))

            if self.ar_min_lag > 1:
                for l in range(2, self.ar_min_lag + 1, 1):
                    df_time_serie = df_time_serie.select(
                        '*',
                        lag('ar' + str(l - 1) + '_number_user_minute').over(
                            w).alias('ar' + str(l) + '_number_user_minute'))
                    df_time_serie = df_time_serie.select(
                        '*',
                        lag('ar' + str(l - 1) + '_number_ads_minute').over(
                            w).alias('ar' + str(l) + '_number_ads_minute'))

        # Remove the lagged Null Values
        df_time_serie = df_time_serie.dropna()

        # join and remove lag Null values of the first minute
        df = df.orderBy(['UserID', 'hms_index'])
        df = df.join(df_time_serie.orderBy(['hm_index']),
                     how='left',
                     on=df.hm_index == df_time_serie.value).drop('value')

        # Convert to time-series and resample by Seconds
        df_time_serie = df.select(
            ['hms_index', 'number_user_second',
             'number_ads_second']).drop_duplicates()
        resample_range = list(
            range(
                df_time_serie.select(min_(
                    col('hms_index'))).limit(1).collect()[0][0],
                df_time_serie.select(max_(
                    col('hms_index'))).limit(1).collect()[0][0] + 1, 1))
        resample_range = self._spark.createDataFrame(resample_range,
                                                     IntegerType())

        # Join the original df
        df_time_serie = resample_range.join(
            df_time_serie,
            how='left',
            on=resample_range.value == df_time_serie.hms_index).drop(
                *['hms_index']).fillna(0)

        # Create lags
        w = Window().partitionBy().orderBy(col('value'))
        if self.ar_lags > 0:
            df_time_serie = df_time_serie.select(
                '*',
                lag('number_user_second').over(w).alias(
                    'ar1_number_user_second'))
            df_time_serie = df_time_serie.select(
                '*',
                lag('number_ads_second').over(w).alias(
                    'ar1_number_ads_second'))

            if self.ar_lags > 1:
                for l in range(2, self.ar_lags + 1, 1):
                    df_time_serie = df_time_serie.select(
                        '*',
                        lag('ar' + str(l - 1) + '_number_user_second').over(
                            w).alias('ar' + str(l) + '_number_user_second'))
                    df_time_serie = df_time_serie.select(
                        '*',
                        lag('ar' + str(l - 1) + '_number_ads_second').over(
                            w).alias('ar' + str(l) + '_number_ads_second'))

        # Create Moving Average
        if self.ma_ss_lag is not None:

            # Get hour from index
            func_index = udf(lambda x: auxiliar_func.num_to_time(x),
                             StringType())
            df_time_serie = df_time_serie.withColumn(
                'time', func_index(df_time_serie['value']))

            # minute MA terms (Average per second last xx seconds)
            if self.ma_ss_lag is not None:
                for lag_val in self.ma_ss_lag:
                    # range to take into account
                    w = (Window.orderBy(df_time_serie['value']).rangeBetween(
                        -lag_val, 0))
                    # MA variables
                    df_time_serie = df_time_serie.withColumn(
                        'ma_seconds_' + str(lag_val) + '_number_user_second',
                        avg('number_user_second').over(w))
                    df_time_serie = df_time_serie.withColumn(
                        'ma_seconds_' + str(lag_val) + '_number_ads_second',
                        avg('number_ads_second').over(w))

                    # Increasing ID
                    df_time_serie = df_time_serie.withColumn(
                        'rn', monotonically_increasing_id())

                    # Replace first values by Null
                    df_time_serie = df_time_serie.withColumn(
                        'ma_seconds_' + str(lag_val) + '_number_user_second',
                        when(df_time_serie['rn'] < lag_val, None).otherwise(
                            df_time_serie['ma_seconds_' + str(lag_val) +
                                          '_number_user_second']))

                    df_time_serie = df_time_serie.withColumn(
                        'ma_seconds_' + str(lag_val) + '_number_ads_second',
                        when(df_time_serie['rn'] < lag_val, None).otherwise(
                            df_time_serie['ma_seconds_' + str(lag_val) +
                                          '_number_ads_second']))

                    # Get the average by Minute
                    df_time_serie = df_time_serie.withColumn(
                        'ma_minute_' + str(lag_val) + '_number_user_second',
                        df_time_serie['ma_seconds_' + str(lag_val) +
                                      '_number_user_second'] * 60)
                    df_time_serie = df_time_serie.withColumn(
                        'ma_minute_' + str(lag_val) + '_number_ads_second',
                        df_time_serie['ma_seconds_' + str(lag_val) +
                                      '_number_ads_second'] * 60)
                df_time_serie = df_time_serie.drop(*['rn'])

        # Remove the lagged Null Values
        df_time_serie = df_time_serie.drop(
            *['time', 'number_user_second', 'number_ads_second']).dropna()
        # join and remove lag Null values of the first minute
        df = df.join(
            df_time_serie.orderBy(['value']),
            how='left',
            on=df.hms_index == df_time_serie.value).drop('value').dropna()

        if self.train_file and not self.variable_analysis:
            df = df.select([
                'key_id', 'hms_index', 'number_ads_user', 'number_user_second',
                'number_ads_second', 'number_ads_user_second', 'peak6am8am',
                'peak14pm16pm', 'user_id_acumulative'
            ] + [x for x in df.columns if x.startswith('d_browser')] +
                           [x for x in df.columns if x.startswith('ar')] +
                           [x for x in df.columns if x.startswith('ma_')] +
                           ['WinningBid'])

        if not self.train_file:
            df = df.filter(df['test'] == 1)
            df = df.select([
                'UserID', 'key_id', 'number_ads_user', 'hms_index',
                'number_user_second', 'number_ads_second',
                'number_ads_user_second', 'peak6am8am', 'peak14pm16pm',
                'user_id_acumulative'
            ] + [x for x in df.columns if x.startswith('d_browser')] +
                           [x for x in df.columns if x.startswith('ar')] +
                           [x for x in df.columns if x.startswith('ma_')])

        df = df.orderBy(['hms_index', 'UserID'])
        df.show()
        return df
예제 #5
0
    def transform_data(self, df, bl_processed, peritos_aux, perito_nif_aux,
                       reparador_aux):
        """Transform original dataset.

        :param df: Input DataFrame.
        :return: Transformed DataFrame.
        """
        # Cast key variables and rename headers
        df = df.withColumnRenamed('auditCodigoSiniestroReferencia',
                                  'id_siniestro')
        df = df.withColumn('id_siniestro', df.id_siniestro.cast(IntegerType()))
        df = df.withColumn(
            'peritaje_transferencia_IBAN',
            regexp_replace('peritaje_transferencia_IBAN', ' ', ''))
        df = df.fillna({'peritaje_transferencia_IBAN': 0})
        df = df.withColumn('peritaje_transferencia_IBAN',
                           df['peritaje_transferencia_IBAN'].cast('float'))
        df = df.withColumn('peritaje_transferencia_nif',
                           df['peritaje_transferencia_nif'].cast('string'))
        df = df.withColumn('peritaje_codigo',
                           df['peritaje_codigo'].cast(IntegerType()))

        # VARIABLES DE FECHA
        fecha_variables = ['fecha_encargo_peritaje', 'peritaje_fecha_informe']
        func = udf(lambda x: datetime.datetime.strptime(x, '%Y/%m/%d'),
                   DateType())
        for col in fecha_variables:
            df = df.fillna({col: '1900/01/01'})
            df = df.withColumn(col, func(df[col]))
            df = df.withColumn(
                col,
                when(df[col] == '1900-01-01', None).otherwise(df[col]))

        # Sort Values by Perito-Visita
        df = df.orderBy(['id_siniestro', 'peritaje_codigo'],
                        ascending=[True, True])

        # INFORME DEFINITIVO exist: First we count the null informe_definitivo. Then we cumulate the values.
        # Finally, we replace positive values with one, because we just want to identify.
        df = df.withColumn(
            'peritaje_no_informe_definitivo',
            when(df['peritaje_fecha_informe'].isNull(), 1).otherwise(0))
        w = (Window().partitionBy(df.id_siniestro).rowsBetween(
            -sys.maxsize, sys.maxsize))

        df = df.withColumn('peritaje_no_informe_definitivo',
                           sum_(df.peritaje_no_informe_definitivo).over(w))
        df = df.withColumn(
            'peritaje_no_informe_definitivo',
            when(df['peritaje_no_informe_definitivo'] > 0, 1).otherwise(0))

        # COUNT PERITAJES: We count the adjust-loss visits using the number of times is repeated a sinister.
        df = df.withColumn('peritaje_pondera', lit(1))
        df = df.withColumn('peritaje_count', sum_(df.peritaje_pondera).over(w))

        # FECHA PRIMER PERITAJE - ULTIMO PERITAJE: To each sinister we just keep the first date of the adjust-loss
        # visit and the last date.
        # First Date: We create a table that only keep the sinister and the first date. Then we remarge keeping the
        # first value of each sinister
        fecha_primer_df = df.select(['id_siniestro', 'fecha_encargo_peritaje'])
        fecha_primer_df = fecha_primer_df.orderBy(
            ['id_siniestro', 'fecha_encargo_peritaje'],
            ascending=[True, False])
        fecha_primer_df = fecha_primer_df.dropDuplicates(
            subset=['id_siniestro'])
        fecha_primer_df = fecha_primer_df.withColumnRenamed(
            'fecha_encargo_peritaje', 'fecha_primer_peritaje')
        df = df.join(fecha_primer_df, on='id_siniestro', how='left')
        del fecha_primer_df

        fecha_ultimo_df = df.select(['id_siniestro', 'peritaje_fecha_informe'])
        fecha_ultimo_df = fecha_ultimo_df.orderBy(
            ['id_siniestro', 'peritaje_fecha_informe'],
            ascending=[True, False])
        fecha_ultimo_df = fecha_ultimo_df.dropDuplicates(
            subset=['id_siniestro'])
        fecha_ultimo_df = fecha_ultimo_df.withColumnRenamed(
            'peritaje_fecha_informe', 'fecha_ultimo_informe')
        df = df.join(fecha_ultimo_df, on='id_siniestro', how='left')
        del fecha_ultimo_df

        # TIEMPO ENTRE PERITAJES: fecha_ultimo_informe - fecha_primer_peritaje
        df = df.withColumn(
            'peritaje_duracion',
            datediff(df['fecha_ultimo_informe'], df['fecha_primer_peritaje']))

        # DURACION PROMEDIO PERITAJE: We calculate the duration time average by number of visits in each sinister
        df = df.withColumn('peritaje_duracion_promedio',
                           df['peritaje_duracion'] / df['peritaje_count'])

        # FECHA_INFORME EXTENDIDA: We convert fecha_informe_encargo_extendida into two values S = 1, N = 0
        df = df.withColumn(
            'fecha_informe_encargo_extendida',
            when(df['fecha_informe_encargo_extendida'] == 'S', 1).otherwise(0))
        df = df.withColumn('fecha_informe_encargo_extendida',
                           sum_(df.fecha_informe_encargo_extendida).over(w))

        # CATEGORICAL VAR: Using dummy variables, we generate the cumsum and the average of each value. 'count' will
        # count the total value summing each survey visit value. 'promedio' will take the average of surveys in
        # each sinister
        var_dummies = [
            'peritaje_pregunta_1', 'peritaje_pregunta_2',
            'peritaje_pregunta_3', 'peritaje_pregunta_4',
            'peritaje_pregunta_5', 'peritaje_pregunta_6a',
            'peritaje_pregunta_7', 'peritaje_pregunta_8a',
            'peritaje_pregunta_9', 'peritaje_pregunta_10',
            'peritaje_pregunta_11', 'peritaje_pregunta_12',
            'peritaje_pregunta_13', 'peritaje_pregunta_14',
            'peritaje_pregunta_15', 'peritaje_pregunta_16',
            'peritaje_pregunta_17', 'peritaje_pregunta_18',
            'peritaje_pregunta_19', 'peritaje_pregunta_20',
            'peritaje_negativo', 'peritaje_posible_fraude',
            'peritaje_negativos_perito'
        ]

        for col in var_dummies:
            # We generate a table dummy so we can drop the nan values and therefore we do not take into account
            # this values on sum and average value
            dummie_sum = df.select(['id_siniestro', col])

            # We drop the nan values in each loss adjuster visit
            dummie_sum = dummie_sum.dropna(subset=[col])

            # Now we count how many surveys were made
            dummie_sum = dummie_sum.withColumn('peritaje_pondera', lit(1))
            w_dummy = (Window().partitionBy(
                dummie_sum.id_siniestro).rowsBetween(-sys.maxsize,
                                                     sys.maxsize))
            dummie_sum = dummie_sum.withColumn(
                'peritaje_count',
                sum_(dummie_sum.peritaje_pondera).over(w_dummy))

            # We take the total sum and the average
            name = col + '_count'
            promedio = col + '_promedio'
            if col != 'peritaje_negativos_perito':
                dummie_sum = dummie_sum.withColumn(
                    col, dummie_sum[col].cast(IntegerType()))
            else:
                dummie_sum = dummie_sum.withColumn(
                    col, dummie_sum[col].cast('float'))

            dummie_sum = dummie_sum.withColumn(
                name,
                sum_(dummie_sum[col]).over(w_dummy))
            dummie_sum = dummie_sum.withColumn(
                promedio, dummie_sum[name] / dummie_sum['peritaje_count'])

            # We delete peritaje_count and pondera so we do not have problem with the merge
            dummie_sum = dummie_sum.drop(
                *[col, 'peritaje_count', 'peritaje_pondera'])

            # We drop the duplicates values in each siniester and keep the last which is the value that cumsum the total
            # values
            dummie_sum = dummie_sum.dropDuplicates(subset=['id_siniestro'])

            # We merge the table with the original dataframe
            df = df.join(dummie_sum, on='id_siniestro', how='left')
            del dummie_sum

        # PERITAJE_NEGATIVO: If peritaje_negativo_count > 0 => peritaje_negativo = 1
        df = df.withColumn(
            'peritaje_negativo',
            when(df['peritaje_negativo_count'] > 0, 1).otherwise(0))

        # PERITAJE NEGATIVO PERITO: We made delete the sum count, we just need the average
        df = df.drop('peritaje_negativos_perito_count')

        # IBAN DE PERITO: We check if the adjust losser's IBAN is registred in the blacklist
        bl_processed_iban = bl_processed.filter(~(
            (bl_processed['iban'].isNull()) | (bl_processed['iban'] == '?')))
        bl_processed_iban = bl_processed_iban.select('iban')
        bl_processed_iban = bl_processed_iban.dropDuplicates(subset=['iban'])
        df = df.join(bl_processed_iban,
                     df.peritaje_transferencia_IBAN == bl_processed_iban.iban,
                     how='left')
        df = df.withColumn('peritaje_iban_blacklist',
                           when(df['iban'].isNull(), 0).otherwise(1))

        # PERITAJE INDEM INFORME PREVIO: We sum the total values
        df = df.withColumn('peritaje_indem_informe_previo',
                           df['peritaje_indem_informe_previo'].cast('float'))
        df = df.withColumn('peritaje_indem_informe_previo_sum',
                           sum_(df['peritaje_indem_informe_previo']).over(w))

        # PERIAJTE_INDEM_INFORME_DEFNITIVO: We sum the total values
        df = df.withColumn(
            'peritaje_indem_informe_definitivo',
            df['peritaje_indem_informe_definitivo'].cast('float'))
        df = df.withColumn(
            'peritaje_indem_informe_definitivo_sum',
            sum_(df['peritaje_indem_informe_definitivo']).over(w))

        # DIFERENCIA DEFINITIVO-PREVIO
        df = df.withColumn(
            'peritaje_indem_previo_definitivo_sum',
            df['peritaje_indem_informe_definitivo_sum'] -
            df['peritaje_indem_informe_previo_sum'])

        # COBERTURAS: valores extraños
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_previo',
            df['peritaje_coberturas_indemnizar_previo'].cast(IntegerType()))
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_MIGRA',
            when(df['peritaje_coberturas_indemnizar_previo'] > 7,
                 1).otherwise(0))
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_previo',
            when(df['peritaje_coberturas_indemnizar_previo'] > 10,
                 df['peritaje_coberturas_indemnizar_definitivo']).otherwise(
                     df['peritaje_coberturas_indemnizar_previo']))

        # COBERTURAS INFORME PREVIO
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_previo',
            df['peritaje_coberturas_indemnizar_previo'].cast('float'))
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_previo_sum',
            sum_(df.peritaje_coberturas_indemnizar_previo).over(w))
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_previo_promedio',
            df['peritaje_coberturas_indemnizar_previo_sum'] /
            df['peritaje_count'])

        # COBERTURAS INFORME DEFINITIVO
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_definitivo',
            df['peritaje_coberturas_indemnizar_definitivo'].cast('float'))
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_definitivo_sum',
            sum_(df.peritaje_coberturas_indemnizar_definitivo).over(w))
        df = df.withColumn(
            'peritaje_coberturas_indemnizar_definitivo_promedio',
            df['peritaje_coberturas_indemnizar_definitivo_sum'] /
            df['peritaje_count'])

        # DIFERENCIA COBERTURAS DEFINITIVO-PREVIO
        df = df.withColumn(
            'peritaje_cobertura_previo_definitivo_sum',
            df['peritaje_coberturas_indemnizar_definitivo_sum'] -
            df['peritaje_coberturas_indemnizar_previo_sum'])

        # PORCENTUAL VARIATION INDEM-COBERTURAS: Here we make the difference betweeen the last visit. So we do not have
        # to acumulate the values. We take the variation and, at the end, we keep the last row. We have to normalize to
        # avoid the zero division problem. For COBERTURAS, due it is an int value we can get the % value for zero
        # division with the diff. However, for INDEM, it can generate extra large values, so we left it in Zero.

        funct_indem = udf(
            lambda x_definitivo, x_previo: x_definitivo / x_previo - 1
            if x_previo != 0 else 0., FloatType())
        funct_garan = udf(
            lambda x_definitivo, x_previo, x_final_inicial: x_definitivo /
            x_previo - 1 if x_previo != 0 else x_final_inicial, FloatType())

        df = df.withColumn(
            'peritaje_indem_final_inicial',
            funct_indem(df.peritaje_indem_informe_definitivo,
                        df.peritaje_indem_informe_previo))
        df = df.withColumn(
            'peritaje_garantia_final_inicial',
            funct_garan(df.peritaje_coberturas_indemnizar_definitivo,
                        df.peritaje_coberturas_indemnizar_previo,
                        df.peritaje_garantia_final_inicial))
        df = df.withColumn(
            'peritaje_indem_final_inicial',
            funct_garan(df.peritaje_coberturas_indemnizar_definitivo,
                        df.peritaje_coberturas_indemnizar_previo,
                        df.peritaje_garantia_final_inicial))

        # PERITO EN BLACKLIST POR NIF: We count how many times the loss-adjuster NIF appears in the historic blacklist
        bl_processed = bl_processed.select('nif_o_intm')
        bl_processed = bl_processed.dropDuplicates(subset=['nif_o_intm'])
        df = df.join(bl_processed,
                     df.peritaje_transferencia_nif == bl_processed.nif_o_intm,
                     how='left')
        df = df.withColumn('perito_fraud_claims',
                           when(df['nif_o_intm'].isNull(), 0).otherwise(1))

        perito_base = df.select([
            'id_siniestro', 'peritaje_nombre', 'peritaje_transferencia_nif',
            'peritaje_aide_nombre_reparador', 'peritaje_pondera',
            'peritaje_negativo', 'peritaje_indem_informe_definitivo',
            'peritaje_coberturas_indemnizar_definitivo'
        ])

        df = df.dropDuplicates(subset='id_siniestro')

        # TABLA DE PERITOS BY AGRUPACION: Some statistics about the loss-adjuster only for the current DB
        if self._is_prediction:
            df = df.join(peritos_aux, on='peritaje_nombre', how='left')
            peritos_cols = list(peritos_aux.columns)
            peritos_cols.remove('peritaje_nombre')
            for col in peritos_cols:
                df = df.fillna({col: 0})
            del peritos_cols

        else:
            peritos = perito_base.select([
                'id_siniestro', 'peritaje_nombre', 'peritaje_pondera',
                'peritaje_negativo', 'peritaje_indem_informe_definitivo',
                'peritaje_coberturas_indemnizar_definitivo'
            ])

            # paso 1: Eliminar NaN
            peritos = peritos.dropna(subset='peritaje_nombre')

            # How many visits by PERITAJE_NOMBRE
            w_peritos = (Window().partitionBy(
                peritos.peritaje_nombre).rowsBetween(-sys.maxsize,
                                                     sys.maxsize))
            peritos = peritos.withColumn(
                'peritaje_count_visitasxperito',
                sum_(df.peritaje_pondera).over(w_peritos))

            # How many negative claims by PERITAJE_NOMBRE
            peritos_temp = peritos.filter(
                ~peritos['peritaje_negativo'].isNull())
            peritos_temp = peritos_temp.withColumn(
                'peritaje_negativo',
                df['peritaje_negativo'].cast(IntegerType()))
            w_peritos_temp = (
                Window().partitionBy('peritaje_nombre').rowsBetween(
                    -sys.maxsize, sys.maxsize))
            peritos_temp = peritos_temp.withColumn(
                'peritaje_count_negativoxperito',
                sum_(df.peritaje_negativo).over(w_peritos_temp))
            peritos_temp = peritos_temp.fillna(
                {'peritaje_count_negativoxperito': 0})
            peritos_temp = peritos_temp.select(
                ['peritaje_nombre', 'peritaje_count_negativoxperito'])
            peritos_temp = peritos_temp.dropDuplicates(
                subset='peritaje_nombre')
            peritos = peritos.join(peritos_temp,
                                   on='peritaje_nombre',
                                   how='left')
            del peritos_temp, w_peritos_temp

            peritos = peritos.drop('peritaje_negativo')

            # Average of Negative Surveys by PERITAJE_NOMBRE
            peritos = peritos.withColumn(
                'peritaje_perito_porc_negativos',
                peritos['peritaje_count_negativoxperito'] /
                peritos['peritaje_count_visitasxperito'])

            # Amount of Indem definitiva by PERITAJE_NOMBRE
            peritos = peritos.withColumn(
                'peritaje_sum_indem_definitivaxperito',
                sum_('peritaje_indem_informe_definitivo').over(w_peritos))
            peritos = peritos.drop('peritaje_indem_informe_definitivo')

            # Amount of Coberturas by PERITAJE_ NOMBRE
            peritos = peritos.withColumn(
                'peritaje_sum_coberturaxperito',
                sum_('peritaje_coberturas_indemnizar_definitivo').over(
                    w_peritos))
            peritos = peritos.drop('peritaje_coberturas_indemnizar_definitivo')

            # paso 2: Mantenemos el último siniestro para poder agrupar el fraude por siniestro
            peritos = peritos.dropDuplicates(
                subset=['id_siniestro', 'peritaje_nombre'])

            # How many claims by PERITAJE_NOMBRE
            w_peritos = (Window().partitionBy(
                peritos.peritaje_nombre).rowsBetween(-sys.maxsize,
                                                     sys.maxsize))
            peritos = peritos.withColumn(
                'peritaje_count_siniestrosxperito',
                sum_(df.peritaje_pondera).over(w_peritos))
            peritos = peritos.drop('peritaje_pondera')

            # Average of Indem definitiva by PERITAJE_NOMBRE
            peritos = peritos.withColumn(
                'peritaje_promedio_indem_definitivaxperito',
                peritos['peritaje_sum_indem_definitivaxperito'] /
                peritos['peritaje_count_siniestrosxperito'])

            # We merge with the known cases of Fraud
            file_blacklist_resume = bl_processed.select('id_siniestro')
            file_blacklist_resume = file_blacklist_resume.dropDuplicates(
                subset='id_siniestro')
            file_blacklist_resume = file_blacklist_resume.withColumn(
                'peritos_fraud', lit(1))
            peritos = peritos.join(file_blacklist_resume,
                                   on='id_siniestro',
                                   how='left')
            peritos = peritos.fillna({'peritos_fraud': 0})

            # How many fraud sinister by PERITAJE_NOMBRE
            peritos = peritos.withColumn(
                'peritaje_count_FRAUDxperito',
                sum_(peritos['peritos_fraud']).over(w_peritos))

            # Average fraud sinister by PERITAJE_NOMBRE
            peritos = peritos.withColumn(
                'peritaje_promedio_FRAUDxsiniestroxperito',
                peritos['peritaje_count_FRAUDxperito'] /
                peritos['peritaje_count_siniestrosxperito'])

            # We get the values by PERITAJE_NOMBRE and calculate
            # paso 3: mantenemos solo al perito
            peritos_temp = peritos.dropDuplicates(subset=['peritaje_nombre'])
            peritos_temp = outliers.Outliers.outliers_mad(
                peritos_temp,
                'peritaje_promedio_FRAUDxsiniestroxperito',
                not_count_zero=False)
            peritos_temp = outliers.Outliers.outliers_mad(
                peritos_temp,
                'peritaje_promedio_indem_definitivaxperito',
                not_count_zero=False)
            peritos_temp = outliers.Outliers.outliers_mad(
                peritos_temp,
                'peritaje_sum_coberturaxperito',
                not_count_zero=False)
            peritos_temp = peritos_temp.drop('id_siniestro')
            peritos = peritos.select(['id_siniestro', 'peritaje_nombre'])
            peritos = peritos.join(peritos_temp,
                                   on='peritaje_nombre',
                                   how='left')
            del peritos_temp

            peritos = peritos.dropDuplicates(subset=['peritaje_nombre'])
            peritos = peritos.drop('id_siniestro')

            df = df.join(peritos, on='peritaje_nombre', how='left')
            peritos_cols = list(peritos.columns)
            peritos_cols.remove('peritaje_nombre')
            for col in peritos_cols:
                df = df.fillna({col: 0})
            del peritos_cols

        # TABLA DE PERITOS BY AGRUPACION: Some statistics about the loss-adjuster only for the current DB
        if self._is_prediction:
            df = df.join(perito_nif_aux,
                         how='left',
                         on='peritaje_transferencia_nif')
            peritos_cols = perito_nif_aux.columns.values.tolist()
            peritos_cols.remove('peritaje_transferencia_nif')
            for col in peritos_cols:
                df = df.fillna({col: 0})
            del peritos_cols

        else:
            perito_nif = perito_base.select([
                'id_siniestro', 'peritaje_transferencia_nif',
                'peritaje_pondera', 'peritaje_negativo',
                'peritaje_indem_informe_definitivo',
                'peritaje_coberturas_indemnizar_definitivo'
            ])

            # paso1: Eliminar NaN
            perito_nif = perito_nif.dropna(subset='peritaje_transferencia_nif')

            # How many visits by PERITAJE_NOMBRE
            w_peritos = (Window().partitionBy(
                perito_nif.peritaje_transferencia_nif).rowsBetween(
                    -sys.maxsize, sys.maxsize))
            perito_nif = perito_nif.withColumn(
                'peritaje_count_visitasxnif',
                sum_(perito_nif['peritaje_pondera']).over(w_peritos))

            # How many negative claims by PERITAJE_NIF
            peritos_temp = perito_nif.filter(
                ~perito_nif['peritaje_negativo'].isNull())
            w_peritos_temp = (Window().partitionBy(
                peritos_temp.peritaje_transferencia_nif).rowsBetween(
                    -sys.maxsize, sys.maxsize))
            peritos_temp = peritos_temp.withColumn(
                'peritaje_negativo',
                peritos_temp['peritaje_negativo'].cast(IntegerType()))
            peritos_temp = peritos_temp.withColumn(
                'peritaje_nif_count_negativoxperito',
                sum_(peritos_temp['peritaje_negativo']).over(w_peritos_temp))
            peritos_temp = peritos_temp.fillna(
                {'peritaje_nif_count_negativoxperito': 0})
            peritos_temp = peritos_temp.select([
                'peritaje_transferencia_nif',
                'peritaje_nif_count_negativoxperito'
            ])
            peritos_temp = peritos_temp.dropDuplicates(
                subset=['peritaje_transferencia_nif'])
            perito_nif = perito_nif.join(peritos_temp,
                                         on='peritaje_transferencia_nif',
                                         how='left')
            del peritos_temp, w_peritos_temp

            perito_nif = perito_nif.drop('peritaje_negativo')

            # Average of Negative Surveys by PERITAJE_NIF
            perito_nif = perito_nif.withColumn(
                'peritaje_nif_perito_porc_negativos',
                perito_nif['peritaje_nif_count_negativoxperito'] /
                perito_nif['peritaje_count_visitasxnif'])

            # Amount of Indem definitiva by PERITAJE_NIF
            perito_nif = perito_nif.withColumn(
                'peritaje_indem_informe_definitivo',
                perito_nif['peritaje_indem_informe_definitivo'].cast(
                    FloatType()))
            perito_nif = perito_nif.withColumn(
                'peritaje_nif_sum_indem_definitivaxperito',
                sum_(perito_nif['peritaje_indem_informe_definitivo']).over(
                    w_peritos))
            perito_nif = perito_nif.drop('peritaje_indem_informe_definitivo')

            # Amount of Coberturas by PERITAJE_ NIF
            perito_nif = perito_nif.withColumn(
                'peritaje_nif_sum_coberturaxperito',
                sum_(perito_nif['peritaje_coberturas_indemnizar_definitivo']).
                over(w_peritos))
            peritos_nif = perito_nif.drop(
                'peritaje_coberturas_indemnizar_definitivo')

            # paso 2: Mantenemos el último siniestro para poder agrupar el fraude por siniestro
            # How many claims by PERITAJE_NIF
            perito_nif = perito_nif.withColumn(
                'peritaje_nif_count_siniestrosxperito',
                sum_(perito_nif['peritaje_pondera']).over(w_peritos))
            perito_nif = perito_nif.drop('peritaje_pondera')

            # Average of Indem definitiva by PERITAJE_NIF
            perito_nif = perito_nif.withColumn(
                'peritaje_nif_promedio_indem_definitivaxperito',
                perito_nif['peritaje_nif_sum_indem_definitivaxperito'] /
                perito_nif['peritaje_nif_count_siniestrosxperito'])

            # Average of Coberturas by PERITAJE_ NIF
            perito_nif = perito_nif.withColumn(
                'peritaje_nif_promedio_coberturaxperito',
                perito_nif['peritaje_nif_sum_coberturaxperito'] /
                perito_nif['peritaje_nif_count_siniestrosxperito'])

            perito_nif = perito_nif.dropDuplicates(
                subset=['id_siniestro', 'peritaje_transferencia_nif'])

            # We merge with the known cases of Fraud
            file_blacklist_resume = file_blacklist_resume.select(
                'id_siniestro')
            file_blacklist_resume = file_blacklist_resume.withColumn(
                'perito_nif_fraud', lit(1))
            perito_nif = perito_nif.join(file_blacklist_resume,
                                         on='id_siniestro',
                                         how='left')
            perito_nif = perito_nif.fillna({'perito_nif_fraud': 0})

            # How many fraud sinister by PERITAJE_NIF
            perito_nif = perito_nif.withColumn(
                'peritaje_nif_count_FRAUDxperito',
                sum_(perito_nif['peritos_fraud']).over(w_peritos))
            perito_nif = perito_nif.drop('peritos_fraud')

            # Average fraud sinister by PERITAJE_NIF
            perito_nif = perito_nif.withColumn(
                'peritaje_nif_promedio_FRAUDxsiniestroxperito',
                perito_nif['peritaje_nif_count_FRAUDxperito'] /
                perito_nif['peritaje_nif_count_siniestrosxperito'])

            # We get the values by PERITAJE_NIF and calculate
            peritos_temp = perito_nif.dropDuplicates(
                subset=['peritaje_transferencia_nif'])
            peritos_temp = peritos_temp.drop('id_siniestro')
            peritos_temp = outliers.Outliers.outliers_mad(
                peritos_temp,
                'peritaje_nif_promedio_FRAUDxsiniestroxperito',
                not_count_zero=False)
            peritos_temp = outliers.Outliers.outliers_mad(
                peritos_temp,
                'peritaje_nif_promedio_indem_definitivaxperito',
                not_count_zero=False)
            peritos_temp = outliers.Outliers.outliers_mad(
                peritos_temp,
                'peritaje_nif_sum_coberturaxperito',
                not_count_zero=False)
            peritos_nif = peritos_nif.select(
                ['id_siniestro', 'peritaje_transferencia_nif'])
            peritos_nif = peritos_nif.join(peritos_temp,
                                           on='peritaje_transferencia_nif',
                                           how='left')
            del peritos_temp

            peritos_nif = peritos_nif.dropDuplicates(
                subset=['peritaje_transferencia_nif'])
            peritos_nif = peritos_nif.drop('id_siniestro')

            # del peritos['peritaje_transferencia_nif']
            df = df.join(peritos_nif,
                         on='peritaje_transferencia_nif',
                         how='left')
            peritos_cols = peritos_nif.columns.values.tolist()
            peritos_cols.remove('peritaje_transferencia_nif')
            for col in peritos_cols:
                df = df.fillna({col: 0})
            del peritos_cols

        # TABLA REPARADOR: Some statistics based on the current database
        if self._is_prediction:
            df = df.join(reparador_aux,
                         how='left',
                         on='peritaje_aide_nombre_reparador')
            reparador_cols = reparador_aux.columns.values.tolist()
            reparador_cols.remove('peritaje_aide_nombre_reparador')
            for col in reparador_cols:
                df = df.fillna({col: 0})

        else:
            reparador = perito_base.select([[
                'id_siniestro', 'peritaje_aide_nombre_reparador',
                'peritaje_pondera'
            ]])
            del perito_base

            reparador = reparador.dropna(
                subset='peritaje_aide_nombre_reparador')
            reparador = reparador.dropDuplicates(
                subset=['peritaje_aide_nombre_reparador', 'id_siniestro'])

            # We merge with the known cases of Fraud
            file_blacklist_resume = file_blacklist_resume.select(
                'id_siniestro')
            file_blacklist_resume = file_blacklist_resume.withColumn(
                'reparador_fraud', lit(1))
            reparador = reparador.join(file_blacklist_resume,
                                       on='id_siniestro',
                                       how='left')
            reparador = reparador.fillna({'reparador_fraud': 0})

            w_reparador = (Window().partitionBy(
                reparador.peritaje_aide_nombre_reparador).rowsBetween(
                    -sys.maxsize, sys.maxsize))

            reparador = reparador.withColumn(
                'peritaje_count_visitasxreparador',
                sum_(reparador['peritaje_pondera']).over(w_reparador))
            reparador = reparador.drop('peritaje_pondera')

            reparador = reparador.withColumn(
                'peritaje_count_FRAUDxreparador',
                sum_(df['reparador_fraud']).over(w_reparador))
            reparador = reparador.drop('reparador_fraud')
            reparador = reparador.withColumn(
                'peritaje_promedio_FRAUDxsiniestroxreparador',
                reparador['peritaje_count_FRAUDxreparador'] /
                reparador['peritaje_count_visitasxreparador'])

            reparador = reparador.dropDuplicates(
                subset=['peritaje_aide_nombre_reparador'])
            reparador = outliers.Outliers.outliers_mad(
                reparador,
                'peritaje_promedio_FRAUDxsiniestroxreparador',
                justnot_count_zero=True)
            reparador = reparador.drop('id_siniestro')

            df = df.join(reparador,
                         how='left',
                         on='peritaje_aide_nombre_reparador')
            reparador_cols = reparador.columns.values.tolist()
            reparador_cols.remove('peritaje_aide_nombre_reparador')
            for col in reparador_cols:
                df = df.fillna({col: 0})
            del reparador_cols

        # DELETE VARIABLES
        del_variables = [
            "peritaje_siniestro_causa",
            "peritaje_informe_previo_reserva_estimada",
            'peritaje_informe_previo_origen_siniestro', 'peritaje_pregunta_8b',
            'peritaje_pregunta_6b', "peritaje_obs_documentacion",
            "peritaje_obs_fotos", 'id_poliza', 'version_poliza',
            'peritaje_codigo', 'fecha_encargo_peritaje',
            'peritaje_numero_informe', 'peritaje_fecha_informe',
            'fecha_informe_encargo_extendida', 'peritaje_nombre',
            'peritaje_aide_nombre_reparador', 'peritaje_pregunta_1',
            'peritaje_pregunta_2', 'peritaje_pregunta_3',
            'peritaje_pregunta_4', 'peritaje_pregunta_5',
            'peritaje_pregunta_6a', 'peritaje_pregunta_7',
            'peritaje_pregunta_8a', 'peritaje_pregunta_9',
            'peritaje_pregunta_10', 'peritaje_pregunta_11',
            'peritaje_pregunta_12', 'peritaje_pregunta_13',
            'peritaje_pregunta_14', 'peritaje_pregunta_15',
            'peritaje_pregunta_16', 'peritaje_pregunta_17',
            'peritaje_pregunta_18', 'peritaje_pregunta_19',
            'peritaje_pregunta_20', 'peritaje_posible_fraude',
            'peritaje_negativo', 'peritaje_transferencia_IBAN',
            'peritaje_transferencia_nif', 'peritaje_indem_informe_previo',
            'peritaje_indem_informe_definitivo', 'peritaje_pondera',
            'id_fiscal', 'peritaje_negativos_perito',
            'peritaje_coberturas_indemnizar_previo',
            'peritaje_coberturas_indemnizar_definitivo',
            'audit_siniestro_producto_tecnico',
            'audit_siniestro_codigo_compania'
        ]

        df = df.drop(*del_variables)

        return df, peritos, peritos_nif, reparador
예제 #6
0
    def _transform_data(df, bl_processed):
        """Transform original dataset.

        :param df: Input DataFrame.
        :param bl_processed
        :return: Transformed DataFrame.
        """
        # Cast key variables and rename headers
        df = df.withColumn('mediador_cod_intermediario',
                           df.mediador_cod_intermediario.cast(IntegerType()))
        df = df.orderBy('mediador_cod_intermediario')

        # Count Productos
        df = df.withColumn('pondera_producto', lit(1))
        w_cod_intermediario = (Window().partitionBy(
            df.mediador_cod_intermediario).rowsBetween(-sys.maxsize,
                                                       sys.maxsize))
        df = df.withColumn(
            'mediador_producto_count',
            sum_(df['pondera_producto']).over(w_cod_intermediario))

        # Blacklist
        bl_processed_mediador = bl_processed.filter(
            bl_processed['cod_rol'] == 3)
        bl_processed_mediador = bl_processed_mediador.withColumn(
            'pondera', lit(1))
        bl_processed_mediador = bl_processed_mediador.select(
            ['nif_o_intm', 'pondera'])
        w_mediador = (Window().partitionBy(
            bl_processed_mediador['nif_o_intm']).rowsBetween(
                -sys.maxsize, sys.maxsize))
        bl_processed_mediador = bl_processed_mediador.withColumn(
            'mediador_cod_count_blacklist',
            sum_(bl_processed_mediador['pondera']).over(w_mediador))
        bl_processed_mediador = bl_processed_mediador.dropDuplicates(
            subset=['nif_o_intm'])
        df = df.join(
            bl_processed_mediador,
            df.mediador_cod_intermediario == bl_processed_mediador.nif_o_intm,
            how='left')
        df = df.drop(*['nif_o_intm', 'pondera'])
        df = df.fillna({'mediador_cod_count_blacklist': 0})

        # Estado del mediador
        estado = {
            '1': 'Activo',
            '2': 'Activo',
            '3': 'Inactivo',
            '4': 'Pendiente',
            '5': 'Tramite'
        }
        funct = udf(
            lambda x: f.replace_dict(x, key_values=estado, key_in_value=True),
            StringType())
        df = df.withColumn('mediador_estado', funct(df['mediador_estado']))

        # Dummies var
        dummy_var = [
            'mediador_clase_intermediario', 'mediador_estado',
            'id_agrup_producto'
        ]
        for col in dummy_var:
            df = df.fillna({col: 'No Identificado'})
            df = df.withColumn(col, regexp_replace(col, '0', ''))
            type_d = df.select(col).distinct().collect()
            type_d = [ty[col] for ty in type_d]
            col_list = [
                when(df[col] == ty,
                     1).otherwise(0).alias('d_' + col + '_' + ty)
                for ty in type_d
            ]
            df = df.select(list(df.columns) + col_list)
            df.drop(col)

        # We sum the number of products
        product_names = [
            x for x in list(df.columns) if x.startswith('d_id_agrup_producto')
        ]
        for col in product_names:
            df = df.withColumn(col, sum_(df[col]).over(w_cod_intermediario))

        # Antiguedad del mediador
        today = datetime.date.today()

        funct = udf(lambda x: datetime.datetime.strptime(x, '%Y%m%d'),
                    DateType())
        df = df.withColumn(
            'mediador_fecha_alta',
            when(df['mediador_fecha_alta'].isNull(),
                 '19000101').otherwise(df['mediador_fecha_alta']))
        df = df.withColumn('mediador_fecha_alta',
                           funct(df['mediador_fecha_alta']))
        df = df.withColumn('fecha_hoy', lit(today))
        df = df.withColumn(
            'mediador_antiguedad',
            round_(datediff(df['fecha_hoy'], df['mediador_fecha_alta']) / 365))
        df = df.drop('fecha_hoy')

        # Accumulative float variables
        mediador_nan = df.filter(df['mediador_numero_polizas'].isNull()
                                 )  # Guardamos los mediadores que tienen nulos
        df = df.dropna(subset=['mediador_numero_polizas'])
        float_variables = [
            'mediador_numero_polizas', 'mediador_numero_polizas_vigor',
            'mediador_numero_siniestros', 'mediador_numero_siniestros_fraude',
            'mediador_numero_siniestros_pagados'
        ]
        for col in float_variables:
            name_count = col + '_count'
            df = df.withColumn(
                name_count,
                sum_(df[col].cast(IntegerType())).over(w_cod_intermediario))

        # COUNT BY HOGAR: We now create an additional table to get the statistics for PROPERTY and then remarge
        # (0000000002;HOGAR)
        df_hogar = df.filter(df['id_agrup_producto'] == 2)
        df_hogar = df_hogar.select(*['mediador_cod_intermediario'] +
                                   float_variables)
        float_cols = [
            when(df_hogar[col].isNull(),
                 0).otherwise(df_hogar[col]).alias(col + '_hogar')
            for col in float_variables
        ]

        df_hogar = df_hogar.select(['mediador_cod_intermediario'] + float_cols)
        df = df.dropDuplicates(subset=['mediador_cod_intermediario'])
        df = df.join(df_hogar, on='mediador_cod_intermediario', how='left')

        # 1) STATISTICS SAME SET BY ROW: Here we compare the same set (GLOBAL or HOGAR) respecto to their
        # respectives columns
        poliza_var = [
            'mediador_numero_polizas', 'mediador_numero_polizas_vigor'
        ]
        siniestro_var = [
            'mediador_numero_siniestros', 'mediador_numero_siniestros_fraude',
            'mediador_numero_siniestros_pagados'
        ]

        # a) Global: Need to use '_count'
        # polizas_vigor / polizas_total
        df = df.withColumn(
            'mediador_poliza_vigor_total',
            df['mediador_numero_polizas_vigor_count'] /
            df['mediador_numero_polizas_count'])

        # siniestros / siniestros total
        df = df.withColumn(
            'mediador_siniestros_fraude_total',
            df['mediador_numero_siniestros_fraude_count'] /
            df['mediador_numero_siniestros_count'])

        df = df.withColumn(
            'mediador_siniestros_pagados_total',
            df['mediador_numero_siniestros_pagados_count'] /
            df['mediador_numero_siniestros_count'])

        # siniestros / poliza
        for sin_str in siniestro_var:
            name = sin_str + '/poliza'
            df = df.withColumn(
                name,
                df[sin_str + '_count'] / df['mediador_numero_polizas_count'])

        # b) Hogar: Need to use '_hogar'
        # polizas_vigor / polizas_total
        df = df.withColumn(
            'mediador_poliza_vigor_total_hogar',
            df['mediador_numero_polizas_vigor_hogar'] /
            df['mediador_numero_polizas_hogar'])

        # siniestros / siniestros total

        df = df.withColumn(
            'mediador_siniestros_fraude_total_hogar',
            df['mediador_numero_siniestros_fraude_hogar'] /
            df['mediador_numero_siniestros_hogar'])

        df = df.withColumn(
            'mediador_siniestros_pagados_total_hogar',
            df['mediador_numero_siniestros_pagados_hogar'] /
            df['mediador_numero_siniestros_hogar'])

        # siniestros / poliza
        for sin_str in siniestro_var:
            name = sin_str + '/poliza_hogar'
            df = df.withColumn(
                name,
                df[sin_str + '_hogar'] / df['mediador_numero_polizas_hogar'])

        # 2) STATISTICS SAME SET BY COLUMN: We compare the relative weight to the specific column.
        # a) Global:
        for i in poliza_var:
            var = i + '_count'
            name = i + '_weight'
            # Solucion al error de array_list
            total = df.select(var).groupBy().agg(
                sum_(var).alias("total")).collect()
            df = df.withColumn(name, df[var] / total[0].total)

        for i in siniestro_var:
            var = i + '_count'
            name = i + '_weight'
            total = df.select(var).groupBy().agg(
                sum_(var).alias("total")).collect()
            df = df.withColumn(name, df[var] / total[0].total)

        # b) Hogar:
        for i in poliza_var:
            var = i + '_hogar'
            name = i + '_weight'
            total = df.select(var).groupBy().agg(
                sum_(var).alias("total")).collect()
            df = df.withColumn(name, df[var] / total[0].total)

        for i in siniestro_var:
            var = i + '_hogar'
            name = var + '_weight'
            total = df.select(var).groupBy().agg(
                sum_(var).alias("total")).collect()
            df = df.withColumn(name, df[var] / total[0].total)

        # STATISTICS DIFFERENT SETS BY COLUMN: Here we compare the relatives between HOGAR / GLOBAL
        for i in poliza_var:
            global_var = i + '_count'
            hogar_var = i + '_hogar'
            name = i + 'hogar/total'
            df = df.withColumn(name, df[hogar_var] / df[global_var])

        for i in siniestro_var:
            global_var = i + '_count'
            hogar_var = i + '_hogar'
            name = i + 'hogar/total'
            df = df.withColumn(name, df[hogar_var] / df[global_var])

        # OUTLIERS
        for i in poliza_var:
            global_var = i + '_count'
            hogar_var = i + '_hogar'
            df = outliers.Outliers.outliers_mad(df,
                                                global_var,
                                                not_count_zero=False)
            df = outliers.Outliers.outliers_mad(df,
                                                hogar_var,
                                                not_count_zero=False)

        for i in siniestro_var:
            global_var = i + '_count'
            hogar_var = i + '_hogar'
            df = outliers.Outliers.outliers_mad(df,
                                                global_var,
                                                not_count_zero=False)
            df = outliers.Outliers.outliers_mad(df,
                                                hogar_var,
                                                not_count_zero=False)

        # Unimos otra vez los mediadores que tienen nulos
        for col in list(df.columns):
            if col not in list(mediador_nan.columns):
                mediador_nan = mediador_nan.withColumn(col, lit(None))

        df = df.union(mediador_nan)

        # Outlier para el número de veces en la BL
        df = outliers.Outliers.outliers_mad(df,
                                            'mediador_cod_count_blacklist',
                                            not_count_zero=True)

        # DELETE VARIABLES
        del_variables = float_variables + [
            'mediador_denominacion_intermediario',
            'mediador_nif_intermediario', 'mediador_fecha_alta', 'Description',
            'pondera_producto'
        ]
        df = df.drop(*del_variables)
        df = df.fillna(0)

        return df
    mode="DROPMALFORMED", \
    schema=schema \
    )

line_decay_with_dates_df = line_decay_input_df.withColumn("lifespan", clean_string_for_int_udf(col_("lifespan"))) \
    .withColumn("created", clean_string_for_date_udf(col_("created"))) \
    .withColumn("removed", clean_string_for_date_udf(col_("removed"))) \
    .withColumn("create_week", create_cohort_udf(col_("created"))) \
    .withColumn("remove_week", create_cohort_udf(col_("removed")))

create_window = Window.partitionBy().orderBy(col_("create_week"))
lines_created_on_week_df = line_decay_with_dates_df.filter(col_("create_week") != -1) \
    .groupBy(col_("create_week")) \
    .count() \
    .withColumnRenamed("count", "lines_created") \
    .withColumn("running_created", sum_(col_("lines_created")).over(create_window)) \
    .withColumnRenamed("create_week", "week")

#lines_created_on_week_df.show()

remove_window = Window.partitionBy().orderBy(col_("remove_week"))
lines_removed_on_week_df = line_decay_with_dates_df.filter(col_("remove_week") != -1)\
    .groupBy(col_("remove_week")) \
    .count() \
    .withColumnRenamed("count", "lines_removed") \
    .withColumn("running_removed", sum_(col_("lines_removed")).over(remove_window)) \
    .withColumnRenamed("remove_week", "week")

lines_removed_on_week_df.show()

active_lines_df = lines_created_on_week_df.join(lines_removed_on_week_df, "week", "left_outer") \
예제 #8
0
    def transform_data(self, df, df_reserva, df_reserva_new, df_fecha,
                       init_date_new_, init_date_historic_):
        """Transform original dataset.

        :param df: Input DataFrame.
        :param df_reserva
        :param df_reserva_new
        :param df_fecha
        :param init_date_new_: Minimun date for new claims
        :param init_date_historic_: Max historical data
        :return: Transformed DataFrame.
        """
        # Cast key variables and rename headers
        df = df.withColumnRenamed('auditCodigoSiniestroReferencia',
                                  'id_siniestro')
        df = df.withColumn('id_siniestro', df.id_siniestro.cast(IntegerType()))

        # CONSERVED VARIABLES: We drop the variables that are not well defined or that at wrong defined.
        var_conserved = [
            "id_siniestro", 'id_poliza', 'version_poliza',
            "fecha_poliza_emision", "fecha_poliza_efecto_natural",
            "fecha_poliza_efecto_mvto", "fecha_poliza_vto_movimiento",
            "fecha_poliza_vto_natural", "fecha_siniestro_ocurrencia",
            'fecha_siniestro_comunicacion', "fecha_primera_visita_peritaje",
            "fecha_ultima_visita_peritaje"
        ]

        df = df.select(*var_conserved)

        # We fill siniestro_comunicacion with siniestro_ocurrencia
        df = df.withColumn(
            'fecha_siniestro_comunicacion',
            coalesce('fecha_siniestro_comunicacion',
                     'fecha_siniestro_ocurrencia'))

        # STRIP dates: YEAR, MONTH, WEEKDAY, DAY
        var_fecha = [
            "fecha_poliza_emision", "fecha_poliza_efecto_natural",
            "fecha_poliza_efecto_mvto", "fecha_poliza_vto_movimiento",
            "fecha_poliza_vto_natural", "fecha_siniestro_ocurrencia",
            'fecha_primera_visita_peritaje', 'fecha_ultima_visita_peritaje',
            'fecha_siniestro_comunicacion'
        ]

        func = udf(lambda x: datetime.datetime.strptime(x, '%Y/%m/%d'),
                   DateType())

        for col in var_fecha:
            year_name = str(col) + '_year'
            month_name = str(col) + '_month'
            day_name = str(col) + '_day'
            weekday_name = str(col) + '_weekday'
            df = df.fillna({col: '1900/01/01'})
            df = df.withColumn(col, func(df[col]))
            df = df.withColumn(
                col,
                when(df[col] == '1900-01-01', None).otherwise(df[col]))
            df = df.withColumn(year_name, year(df[col]))
            df = df.withColumn(month_name, month(df[col]))
            df = df.withColumn(day_name, dayofmonth(df[col]))
            df = df.withColumn(weekday_name,
                               date_format(col, 'u') -
                               1)  # We adapt to (0=Monday, 1=Tuesday...)
            df = df.withColumn(weekday_name,
                               df[weekday_name].cast(IntegerType()))

        # Filtering by INIT_DATE parameter
        df = df.filter(df['fecha_siniestro_ocurrencia'] >= init_date_historic_)

        # CHECKLIST 6a
        df = df.withColumn('checklist6a', lit(0))
        df = df.withColumn('checklist6a_PP', lit(0))

        # CHECKLIST 6b
        if self._is_diario:
            # Filtering new Claims INIT_DATE
            df = df.filter(
                df['fecha_siniestro_comunicacion'] >= init_date_new_)
            auxiliar_list = checklist_spark.checklist6b(
                df, df_fecha, df_reserva_new, df_reserva)

        else:
            auxiliar_list = checklist_spark.checklist6b(
                None, df, None, df_reserva)

        if auxiliar_list:
            r = Row('id_siniestro_c', 'checklist_6b')
            df_claims = self._spark.createDataFrame(
                r(i, x) for i, x in auxiliar_list)
            df = df.join(df_claims,
                         df.id_siniestro == df_claims.id_siniestro_c,
                         how='left')
            del df_claims, r, auxiliar_list

            df = df.drop('id_siniestro_c')
            df = df.fillna({'checklist_6b': 0})
        else:
            df = df.withColumn('checklist_6b', lit(0))

        # CHECKLIST 7
        if self._is_diario:
            auxiliar_list = checklist_spark.checklist_7(
                df, df_fecha, df_reserva_new, df_reserva)
        else:
            auxiliar_list = checklist_spark.checklist_7(
                None, df, None, df_reserva)

        if auxiliar_list:
            r = Row('id_siniestro', 'checklist_7')
            df_claims = self._spark.createDataFrame(
                r(i, x) for i, x in auxiliar_list)
            del auxiliar_list, r

            df = df.join(df_claims, on='id_siniestro', how='left')
            del df_claims
            df = df.drop('id_siniestro_c')
            df = df.fillna({'checklist_7': 0})
        else:
            df = df.withColumn('checklist_7', lit(0))

        # CHECKLIST 14
        if self._is_diario:
            auxiliar_list = checklist_spark.checklist_14(
                df, df_fecha, df_reserva_new, df_reserva)
        else:
            auxiliar_list = checklist_spark.checklist_14(
                None, df, None, df_reserva)

        if auxiliar_list:
            r = Row('id_siniestro_c', 'checklist_14')
            df_claims = self._spark.createDataFrame(
                r(i, x) for i, x in auxiliar_list)

            w = (Window().partitionBy(df_claims.id_siniestro_c).rowsBetween(
                -sys.maxsize, sys.maxsize))
            df_claims = df_claims.withColumn(
                'checklist_14_coberturas_repetidas',
                sum_(df_claims.checklist_14).over(w))
            df_claims = df_claims.withColumn(
                'checklist_14_siniestros_involucrados',
                count_(df_claims.checklist_14).over(w))
            df_claims = df_claims.dropDuplicates(subset=['id_siniestro_c'])
            df_claims.drop('checklist_14')
            df = df.join(df_claims,
                         df.id_siniestro == df_claims.id_siniestro_c,
                         how='left')
            del df_claims, r, auxiliar_list
            df = df.drop('id_siniestro_c')
            df = df.fillna({'checklist_14_coberturas_repetidas': 0})
            df = df.fillna({'checklist_14_siniestros_involucrados': 0})
        else:
            df = df.withColumn('checklist_14_coberturas_repetidas', lit(0))
            df = df.withColumn('checklist_14_siniestros_involucrados', lit(0))

        # COMPLEX NON-COMPLEX VARIABLES: We define two types of dates. That dates we want more detail we generate
        # every type of possible variable. Non-complex will be more agroupated variables.
        var_fecha_complex = ["fecha_siniestro_ocurrencia"]
        var_fecha_less_complex = [
            "fecha_poliza_efecto_natural", "fecha_poliza_vto_natural"
        ]

        for i in var_fecha_complex:
            # We create dummies
            col_names = [
                str(i) + '_year',
                str(i) + '_month',
                str(i) + '_weekday'
            ]
            for col in col_names:
                types = df.select(col).distinct().collect()
                types = [ty[col] for ty in types]
                type_list = [
                    when(df[col] == ty,
                         1).otherwise(0).alias('d_' + col + '_' + str(ty))
                    for ty in types
                ]
                df = df.select(list(df.columns) + type_list)

            # days range
            day = str(i) + '_day'
            df = df.withColumn(day + '1_10',
                               when(df[day].between(1, 10), 1).otherwise(0))
            df = df.withColumn(day + '10_20',
                               when(df[day].between(11, 20), 1).otherwise(0))
            df = df.withColumn(day + '20_30',
                               when(df[day].between(21, 31), 1).otherwise(0))

        for i in var_fecha_less_complex:
            # month in holiday
            df = df.withColumn(
                str(i) + '_month_holiday',
                when(df[str(i) + '_month'].isin([1, 8, 12]), 1).otherwise(0))

            # days range
            day = str(i) + '_day'
            df = df.withColumn(day + '1_10',
                               when(df[day].between(1, 10), 1).otherwise(0))
            df = df.withColumn(day + '10_20',
                               when(df[day].between(11, 20), 1).otherwise(0))
            df = df.withColumn(day + '20_30',
                               when(df[day].between(21, 31), 1).otherwise(0))

            # weekend or monday
            df = df.withColumn(
                str(i) + '_weekday_weekend',
                when(df[str(i) + '_weekday'].isin([6, 7]), 1).otherwise(0))
            df = df.withColumn(
                str(i) + '_weekday_monday',
                when(df[str(i) + '_weekday'] == 0, 1).otherwise(0))

            # FIRST DELETE: We delete that variables we generated before that are not relevant or are
            # too specific.

        del_variables = [
            'fecha_poliza_emision_year', 'fecha_poliza_emision_month',
            'fecha_poliza_emision_day', 'fecha_poliza_emision_weekday',
            'fecha_poliza_efecto_natural_year',
            'fecha_poliza_efecto_natural_month',
            'fecha_poliza_efecto_natural_day',
            'fecha_poliza_efecto_natural_weekday',
            'fecha_poliza_efecto_mvto_year', 'fecha_poliza_efecto_mvto_month',
            'fecha_poliza_efecto_mvto_day', 'fecha_poliza_efecto_mvto_weekday',
            'fecha_poliza_vto_movimiento_year',
            'fecha_poliza_vto_movimiento_month',
            'fecha_poliza_vto_movimiento_day',
            'fecha_poliza_vto_movimiento_weekday',
            'fecha_poliza_vto_natural_year', 'fecha_poliza_vto_natural_month',
            'fecha_poliza_vto_natural_day', 'fecha_poliza_vto_natural_weekday',
            'fecha_siniestro_ocurrencia_year',
            'fecha_siniestro_ocurrencia_month',
            'fecha_siniestro_ocurrencia_day',
            'fecha_siniestro_ocurrencia_weekday',
            'fecha_primera_visita_peritaje_year',
            'fecha_primera_visita_peritaje_month',
            'fecha_primera_visita_peritaje_day',
            'fecha_primera_visita_peritaje_weekday',
            'fecha_ultima_visita_peritaje_year',
            'fecha_ultima_visita_peritaje_month',
            'fecha_ultima_visita_peritaje_day',
            'fecha_ultima_visita_peritaje_weekday',
            'fecha_siniestro_comunicación_year',
            'fecha_siniestro_comunicación_month',
            'fecha_siniestro_comunicación_day',
            'fecha_siniestro_comunicación_weekday', 'id_poliza',
            'hogar_poblacion', 'version_poliza'
        ]
        df = df.drop(*del_variables)

        # FECHAS LOGICAS: We create different types of dates var that can be relevant to fraud analysis.
        # Diferencia entre primera póliza emisión y último vencimiento natural
        df = df.withColumn(
            'fecha_diferencia_vto_emision',
            datediff(df['fecha_poliza_vto_natural'],
                     df['fecha_poliza_emision']))

        # if fecha efecto < fecha emision => d = 1
        df = df.withColumn(
            'fecha_indicador_efecto_emision',
            when(
                df['fecha_poliza_emision'] > df['fecha_poliza_efecto_natural'],
                1).otherwise(0))

        # diferencia entre siniestro y efecto: 5, 15, 30 días
        df = df.withColumn(
            'fecha_diferencia_siniestro_efecto',
            datediff(df['fecha_siniestro_ocurrencia'],
                     df['fecha_poliza_efecto_natural']))
        days_var = [5, 15, 30]
        for col in days_var:
            df = df.withColumn(
                'fecha_diferencia_siniestro_efecto_' + str(col),
                when(df['fecha_diferencia_siniestro_efecto'] <= col,
                     1).otherwise(0))

        # diferencia entre siniestro y primera emisión: 5, 15, 30 días
        df = df.withColumn(
            'fecha_diferencia_siniestro_emision',
            datediff(df['fecha_siniestro_ocurrencia'],
                     df['fecha_poliza_emision']))
        for col in days_var:
            df = df.withColumn(
                'fecha_diferencia_siniestro_emision_' + str(col),
                when(df['fecha_diferencia_siniestro_emision'] <= col,
                     1).otherwise(0))

        # diferencia entre siniestro y vencimiento 5, 15, 30 días
        df = df.withColumn(
            'fecha_diferencia_siniestro_vto_natural',
            datediff(df['fecha_poliza_vto_natural'],
                     df['fecha_siniestro_ocurrencia']))
        for col in days_var:
            df = df.withColumn(
                'fecha_diferencia_siniestro_vto_natural_' + str(col),
                when(df['fecha_diferencia_siniestro_vto_natural'] <= col,
                     1).otherwise(0))

        # if fecha comunicacion > fecha ocurrencia en 7 días, d = 1
        df = df.withColumn(
            'fecha_diferencia_siniestro_comunicacion',
            datediff(df['fecha_siniestro_comunicacion'],
                     df['fecha_siniestro_ocurrencia']))
        df = df.withColumn(
            'fecha_diferencia_comunicacion_outlier',
            when(df['fecha_diferencia_siniestro_comunicacion'] >= 7,
                 1).otherwise(0))
        df = df.drop('fecha_siniestro_comunicacion')

        df = df.dropDuplicates(subset=['id_siniestro'])

        return df
예제 #9
0
    def _transform_data(self, df, df_base, bl_processed):
        """Transform original dataset.

        :param df: Input DataFrame.
        :param bl_processed
        :return: Transformed DataFrame.
        """

        if self._is_diario:
            df = df.withColumn('TEST', lit(1))
            df_base = df_base.withColumn('TEST', lit(0))
            df = df.union(df_base)

        # Cast key variables and rename headers
        df = df.withColumnRenamed('auditCodigoSiniestroReferencia', 'id_siniestro_ref')
        df = df.withColumn('id_siniestro_ref', df.id_siniestro_ref.cast(IntegerType()))
        df = df.withColumn('id_siniestro', df.id_siniestro.cast(IntegerType()))
        df = df.dropna(subset=['id_siniestro_ref'])
        df = df.dropna(subset=['id_siniestro'])

        # DATE VARIABLES FORMAT
        fecha_variables = ['hist_siniestro_otro_fecha_ocurrencia', 'hist_siniestro_fecha_terminado']
        func = udf(lambda x: datetime.datetime.strptime(x, '%Y/%m/%d'), DateType())
        for col in fecha_variables:
            df = df.fillna({col: '1900/01/01'})
            df = df.withColumn(col, func(df[col]))
            df = df.withColumn(col, when(df[col] == '1900-01-01', None).otherwise(df[col]))
            df = df.filter(df[col] <= time.strftime('%Y-%m-%d'))

        # COUNT ID_SINIESTRO_REF CUANTOS SINIESTROS TIENE
        df = df.withColumn('hist_sin_otros_count_version', lit(1))
        w = (Window().partitionBy(df.id_siniestro_ref).rowsBetween(-sys.maxsize, sys.maxsize))
        df = df.withColumn('hist_sin_otros_count', count_(df.hist_sin_otros_count_version).over(w))

        # SINIESTRO TERMINADO: We transform in dummy variables the category siniestro_sit
        types = df.select('hist_siniestro_otro_sit').distinct().collect()
        types = [ty['hist_siniestro_otro_sit'] for ty in types]
        type_list = [when(df['hist_siniestro_otro_sit'] == ty, 1).otherwise(0).alias('d_hist_siniestro_otro_sit_' + ty)
                     for ty in types]
        df = df.select(list(df.columns) + type_list)

        # DUMMIES ACUMULATIVAS
        types = ['d_hist_siniestro_otro_sit_' + x for x in types]
        var_dummies = ["hist_siniestro_otro_rehusado", "hist_siniestro_otro_bbdd",
                       "hist_siniestro_otro_unidad_investigacion", "hist_siniestro_otro_incidencia_tecnica",
                       "hist_siniestro_otro_incidencia_tecnica_positiva", "hist_siniestro_otro_incidencias",
                       "hist_siniestro_otro_cobertura", "hist_siniestro_otro_rehabilitado"] + types
        for col in var_dummies:
            df = df.withColumn(col + '_count', sum_(df[col]).over(w))
            df = df.drop(col)

        # DATE VARIABLES
        # Duración = Fecha_Terminado - Fecha_Ocurrrencia
        df = df.withColumn('hist_otros_fecha_apertura_terminado', datediff('hist_siniestro_fecha_terminado',
                                                                           'hist_siniestro_otro_fecha_ocurrencia'))

        df = df.withColumn('hist_otros_fecha_apertura_terminado',
                           sum_(df['hist_otros_fecha_apertura_terminado']).over(w))

        # Duración Promedio
        df = df.withColumn('hist_otros_duracion_promedio_sin', df['hist_otros_fecha_apertura_terminado'] /
                           df['hist_sin_otros_count'])

        # Último Siniestro de la póliza: We are going to keep the first row, it is the last sinister.
        df = df.withColumnRenamed('hist_siniestro_otro_fecha_ocurrencia', 'hist_siniestro_otro_ultimo_fecha_ocurrencia')
        df = df.orderBy('hist_siniestro_otro_ultimo_fecha_ocurrencia', ascending=False)

        # FUE UN SINIESTRO FRAUDULENTO? We check if the id_siniestro is associated with a previous Fraud Sinister
        bl_processed = bl_processed.select('id_siniestro').dropDuplicates(subset=['id_siniestro'])
        bl_processed = bl_processed.withColumn('hist_sin_otro_fraude_count', lit(1))
        df = df.join(bl_processed, on='id_siniestro', how='left')
        df = df.withColumn('hist_sin_otro_fraude_count', when(df['hist_sin_otro_fraude_count'].isNull(), 0).otherwise(
            df['hist_sin_otro_fraude_count']))
        df = df.withColumn('hist_sin_otro_fraude_count', sum_(df['hist_sin_otro_fraude_count']).over(w))

        # CARGA SINIESTRAL
        df = df.withColumnRenamed('coste_del_siniestro_por_rol', 'hist_siniestro_carga_siniestral')
        df = df.fillna({'hist_siniestro_carga_siniestral': 0})
        df = df.withColumn('hist_siniestro_carga_siniestral', df.hist_siniestro_carga_siniestral.cast(FloatType()))

        # Construimos el outlier a nivel siniestro: Luego hacemos la suma de los casos de outlier por id_siniestro_ref
        df = outliers.Outliers.outliers_mad(df, 'hist_siniestro_carga_siniestral', not_count_zero=True)
        df = df.withColumn('hist_siniestro_carga_siniestral_mad_outlier_count',
                           sum_(df['hist_siniestro_carga_siniestral_mad_outlier']).over(w))

        # suma total: Sumamos el total de la carga siniestral
        df = df.withColumn('hist_siniestro_carga_siniestral_sum', sum_(df['hist_siniestro_carga_siniestral']).over(w))

        # promedio
        df = df.withColumn('hist_sin_carga_siniestral_promedio', df['hist_siniestro_carga_siniestral_sum']
                           / df['hist_sin_otros_count'])

        # COBERTURAS
        # Outliers
        df = outliers.Outliers.outliers_mad(df, 'hist_siniestro_coberturas_involucradas', not_count_zero=True)
        df = df.withColumn('hist_siniestro_coberturas_involucradas_mad_outlier',
                           when(df['hist_siniestro_coberturas_involucradas'] > 3, 1).otherwise(0))
        df = df.withColumn('hist_siniestro_coberturas_involucradas_mad_outlier_count',
                           sum_(df['hist_siniestro_coberturas_involucradas_mad_outlier']).over(w))
        df = df.drop('hist_siniestro_coberturas_involucradas_mad_outlier')

        # promedio
        df = df.withColumn('hist_sin_otros_cober_sum', sum_(df['hist_siniestro_coberturas_involucradas']).over(w))
        df = df.withColumn('hist_sin_otros_cober_promedio', df['hist_sin_otros_cober_sum'] / df['hist_sin_otros_count'])

        # pagas-cubiertas
        df = df.withColumn('hist_siniestro_coberturas_involucradas_pagadas_sum',
                           sum_(df['hist_siniestro_coberturas_involucradas_pagadas']).over(w))
        df = df.withColumn('hist_sin_otros_pagas_cubiertas',
                           df['hist_siniestro_coberturas_involucradas_pagadas_sum'] / df['hist_sin_otros_cober_sum'])


        # no-pagas
        df = df.withColumn('hist_sin_otros_cob_no_pagas', df['hist_siniestro_coberturas_involucradas'] -
                           df['hist_siniestro_coberturas_involucradas_pagadas'])
        df = df.withColumn('hist_sin_otros_cob_no_pagas', sum_(df['hist_sin_otros_cob_no_pagas']).over(w))

        # VARIABLES DEL
        del_variables = ['id_fiscal', 'hist_siniestro_otro_descripcion', "hist_siniestro_duracion",
                         'hist_siniestro_fecha_terminado', 'hist_sin_otros_count_version',
                         'hist_siniestro_otro_oficina_productora',
                         'hist_siniestro_carga_siniestral', 'hist_siniestro_coberturas_involucradas',
                         'hist_siniestro_coberturas_involucradas_pagadas',
                         'hist_otros_fecha_apertura_terminado',
                         'auditFechaAperturaSiniestroReferencia', 'id_siniestro', 'id_poliza', 'version_poliza',
                         'audit_siniestro_producto_tecnico',
                         'audit_siniestro_codigo_compania', 'hist_siniestro_otro_sit'
                         ]

        df = df.drop(*del_variables)
        df = df.withColumnRenamed('id_siniestro_ref', 'id_siniestro')

        # Tomamos el primero de cada uno de los siniestros
        df = df.dropDuplicates(subset=['id_siniestro'])

        if self._is_diario:
            df = df.filter(df['TEST'] == 1)
            df = df.drop('TEST')

        return df
예제 #10
0
    def _transform_data(self, df, df_base, df_processed, id_base, id_new, bl_processed, aux_perceptor, aux_servicios):
        """Transform original dataset.

        :param df: Input DataFrame.
        :param bl_processed
        :return: Transformed DataFrame.
        """
        # Cast key variables and rename headers
        df = df.withColumn('id_siniestro', df.id_siniestro.cast(IntegerType()))

        if self._is_diario:
            checklist5 = checklist_spark.checklist5(df_reserva=df_base, df_reserva_new=df, df_id=id_base,
                                                    df_id_new=id_new)
        else:
            checklist5 = checklist_spark.checklist5(df_reserva=df, df_id=id_base)

        df = df.join(checklist5, on='id_siniestro', how='left')
        df = df.fillna({'checklist5_poliza': 0, 'checklist5_nif': 0})
        del checklist5

        # RESERVA INICIAL INDEMNIZACION
        reserva_indem = df.select(['id_siniestro', 'po_res_cobertura_id', 'po_res_indem'])
        reserva_indem = reserva_indem.dropDuplicates(subset=['id_siniestro', 'po_res_cobertura_id', 'po_res_indem'])
        reserva_indem = reserva_indem.drop('po_res_cobertura_id')
        reserva_indem = reserva_indem.withColumn('po_res_indem', reserva_indem.po_res_indem.cast(FloatType()))
        reserva_indem = reserva_indem.groupBy(['id_siniestro']).agg(sum_('po_res_indem').alias('po_res_indem'))
        reserva_indem = reserva_indem.withColumn('po_res_indem_mayor_5000',
                                                 when(reserva_indem['po_res_indem'] >= 5000, 1).otherwise(0))
        df = df.drop('po_res_indem')
        df = df.join(reserva_indem, on='id_siniestro', how='left')
        del reserva_indem

        # RESERVA INICIAL GASTO
        reserva_gasto = df.select(['id_siniestro', 'po_res_cobertura_id', 'po_res_gasto'])
        reserva_gasto = reserva_gasto.dropDuplicates(subset=['id_siniestro', 'po_res_cobertura_id', 'po_res_gasto'])
        reserva_gasto = reserva_gasto.drop('po_res_cobertura_id')
        reserva_gasto = reserva_gasto.withColumn('po_res_gasto', reserva_gasto.po_res_gasto.cast(FloatType()))
        reserva_gasto = reserva_gasto.groupBy('id_siniestro').agg(sum_('po_res_gasto').alias('po_res_gasto'))
        reserva_gasto = reserva_gasto.withColumn('po_res_gasto_mayor_1000',
                                                 when(reserva_gasto['po_res_gasto'] >= 1000, 1).otherwise(0))
        reserva_gasto = reserva_gasto.drop('po_res_gasto')
        df = df.join(reserva_gasto, on='id_siniestro', how='left')
        del reserva_gasto

        # COUNT POLIZAS POR SINIESTRO
        df = df.withColumn('pondera_siniestro', lit(1))
        w = (Window().partitionBy('id_siniestro').rowsBetween(-sys.maxsize, sys.maxsize))
        df = df.withColumn('po_reserva_pagoxsiniestro_count', sum_(df['pondera_siniestro']).over(w))
        df = df.withColumn('po_reserva_indemxsiniestro_count', sum_(df['po_pago_indicador_indem']).over(w))
        # PAGO INDEM ANULADOS: Cuando la anulación es == 1 marca tanto el pago como su anulación
        df = df.withColumn('po_pago_indemnizacion_importe_neto',
                           when(df['po_pago_es_anulacion'] == 1, 1).otherwise(df['po_pago_indemnizacion_importe_neto']))

        # GASTO_INDEM_ANULADOS: Cuando el gasto es == 1 marca tanto el pago como su anulación
        df = df.withColumn('po_gasto_indemnizacion_importe_neto',
                           when(df['po_gasto_es_anulacion'] == 1, 1).otherwise(df['po_gasto_es_anulacion']))

        # PAGOS: Sumamos el importe neto de factura + los pagos netos por indemnizaciòn
        df = df.withColumn('po_pago_importe_neto', df['po_pago_factura_importe_neto'].cast(FloatType()) + df[
            'po_pago_indemnizacion_importe_neto'].cast(FloatType()))

        # GASTOS:
        df = df.withColumn('po_gasto_importe_neto', df['po_gasto_factura_importe_neto'].cast(FloatType()) +
                           df['po_gasto_indemnizacion_importe_neto'].cast(FloatType()))

        # PAGO ASEGURADO: Si la persona no es el asegurado ponemos los importes del Asegurado en 0
        df = df.withColumn('po_pago_importe_neto_ASEGURADO',
                           when(df['persona_objeto_asegurado'].cast(IntegerType()) == 0, 0).otherwise(
                               df['po_pago_importe_neto']))

        # IMPORTE PORCENTUAL QUE EFECTIVAMENTE COBRA EL ASEGURADO: importe_neto_asegurado/importe_total
        df = df.withColumn('po_pago_importe_porcentual_ASEGURADO', df['po_pago_importe_neto_ASEGURADO']
                           / (df['po_pago_importe_neto'] + 1))

        # IBAN Blacklist
        bl_processed_iban = bl_processed.filter(~((bl_processed['iban'].isNull()) | (bl_processed['iban'] == '?')))
        bl_processed_iban = bl_processed_iban.select('iban')
        bl_processed_iban = bl_processed_iban.dropDuplicates(subset=['iban'])
        df = df.join(bl_processed_iban, df.po_pago_IBAN == bl_processed_iban.iban, how='left')
        df = df.withColumn('peritaje_pago_iban_blacklist', when(df['iban'].isNull(), 0).otherwise(1))
        df = df.drop('iban')
        df = df.join(bl_processed_iban, df.po_gasto_IBAN == bl_processed_iban.iban, how='left')
        df = df.withColumn('peritaje_gasto_iban_blacklist', when(df['iban'].isNull(), 0).otherwise(1))
        df = df.drop('iban')
        del bl_processed_iban

        # INT Variables
        # Agrupamos los valores INT por Siniestro y lo guardamos en la lista de INT's
        int_var = ['peritaje_pago_iban_blacklist', 'peritaje_gasto_iban_blacklist']
        int_outliers = []

        for col in int_var:
            count = col + '_count'
            df = df.withColumn(count, sum_(df[col]).over(w))
            int_outliers.append(count)
            df = df.drop(col)

        # PERSONA OBJETO RESERVABLE
        df = df.withColumn('id_persona_objeto_reservable_max',
                           max_(df['id_persona_objeto_reservable'].cast(IntegerType())).over(w))
        df = df.drop('id_persona_objeto_reservable')

        # CATEGORICAL VARIABLE
        # Redefinimos la variable pago_gasto_codigo como categórica
        asegurado = STRING.Parameters.Asegurado_Beneficiario_Perjudicado
        profesional = STRING.Parameters.Profesional_Legal
        detective = STRING.Parameters.Detective
        perito = STRING.Parameters.Perito
        reparador = STRING.Parameters.Reparador
        otros = STRING.Parameters.todos

        df = df.withColumn('po_pago_gasto_codigo', df.po_pago_gasto_codigo.cast(StringType()))
        df = df.withColumn('po_pago_gasto_codigo',
                           when(df['po_pago_gasto_codigo'].isin(otros), df['po_pago_gasto_codigo']).otherwise(
                               'Otros'))
        df = df.withColumn('po_pago_gasto_codigo',
                           when(df['po_pago_gasto_codigo'].isin(asegurado),
                                'Asegurado_Beneficiario_Perjudicado').otherwise(df['po_pago_gasto_codigo']))
        df = df.withColumn('po_pago_gasto_codigo',
                           when(df['po_pago_gasto_codigo'].isin(profesional),
                                'Profesional_Legal').otherwise(df['po_pago_gasto_codigo']))
        df = df.withColumn('po_pago_gasto_codigo',
                           when(df['po_pago_gasto_codigo'].isin(detective),
                                'Detective').otherwise(df['po_pago_gasto_codigo']))
        df = df.withColumn('po_pago_gasto_codigo',
                           when(df['po_pago_gasto_codigo'].isin(perito),
                                'Perito').otherwise(df['po_pago_gasto_codigo']))
        df = df.withColumn('po_pago_gasto_codigo',
                           when(df['po_pago_gasto_codigo'].isin(reparador),
                                'Reparador').otherwise(df['po_pago_gasto_codigo']))

        # GARANTIA
        garantia = STRING.Parameters.dict_garantias
        funct = udf(lambda x: f.replace_dict_contain(x, key_values=garantia), StringType())
        df = df.withColumn('po_res_garantia', funct(df['po_res_garantia']))

        # COBERTURA
        cobertura_1 = STRING.Parameters.dict_cobertura_1
        funct = udf(lambda x: f.replace_dict_contain(x, key_values=cobertura_1), StringType())
        df = df.withColumn('po_res_cobertura', funct(df['po_res_cobertura']))
        df = df.withColumn('po_res_cobertura',
                           when(df['po_res_cobertura'] == 'DE', 'ELECTRICIDAD').otherwise(df['po_res_cobertura']))
        cobertura_2 = STRING.Parameters.dict_cobertura_2
        funct = udf(lambda x: f.replace_dict_contain(x, key_values=cobertura_2), StringType())
        df = df.withColumn('po_res_cobertura', funct(df['po_res_cobertura']))

        # Pasamos todas las categóricas para obtener dummies
        categorical_var = ['po_res_garantia', 'po_res_cobertura', 'po_res_situacion',
                           'po_pago_medio', 'po_pago_gasto_codigo']
        variable_dummy = []

        funct = udf(lambda x: f.normalize_string(x), StringType())
        for col in categorical_var:
            df = df.withColumn(col, df[col].cast(StringType()))
            df = df.withColumn(col, funct(df[col]))
            types = df.select(col).distinct().collect()
            types = [ty[col] for ty in types]
            types_list = [when(df[col] == ty, 1).otherwise(0).alias('d_' + col + '_' + ty) for ty in types if
                          ty not in [None, '0', 0]]
            df = df.select(list(df.columns) + types_list)
            variable_dummy += ['d_' + col + '_' + ty for ty in types if ty not in [None, '0', 0]]
            df = df.drop(col)

        # Agrupamos las dummies por siniestro
        variable_dummy += ['po_pago_indicador_indem', 'po_pago_rehusado', 'po_pago_gasto_codigo_detective',
                           'persona_objeto_asegurado']

        for col in variable_dummy:
            name = col + '_count'
            df = df.fillna({col: 0})
            df = df.withColumn(col, df[col].cast(IntegerType()))
            df = df.withColumn(name, sum_(df[col]).over(w))
            df = df.drop(col)

        # Ajustamos las situaciones para representarlo porcentualmente:
        for col in list(df.columns):
            if col.startswith('d_po_res_situacion'):
                df = df.withColumn(col, df[col] / df['po_reserva_pagoxsiniestro_count'])

        # Ajustamos po_pago_indicador_indem para verlo porcentualmente
        df = df.withColumn('po_pago_indicador_indem_count', df['po_pago_indicador_indem_count'] / df[
            'po_reserva_pagoxsiniestro_count'])

        # FLOAT VARIABLES
        # Agrupamos las FLOAT por siniestro y las ponemos para analizar como Outliers
        variable_float_perceptor = ['po_pago_factura_importe_neto', 'po_pago_indemnizacion_importe_neto',
                                    'po_gasto_factura_importe_neto', 'po_gasto_indemnizacion_importe_neto',
                                    'po_pago_importe_neto', 'po_gasto_importe_neto',
                                    'po_pago_importe_neto_ASEGURADO',
                                    'po_pago_importe_porcentual_ASEGURADO',
                                    ]
        float_outliers = []
        for col in variable_float_perceptor:
            name = col + '_count'
            df = df.fillna({col: 0})
            df = df.withColumn(col, df[col].cast(FloatType()))
            df = df.withColumn(name, sum_(df[col]).over(w))
            float_outliers.append(name)

        # Porcentual_Asegurado: Lo ajustamos para que refleje el valor porcentual
        df = df.withColumn('po_pago_importe_porcentual_ASEGURADO_count',
                           df['po_pago_importe_porcentual_ASEGURADO_count'] / df['po_reserva_indemxsiniestro_count'])

        # TABLA DE PERCEPTOR Y SERVICIOS
        df = df.withColumn('po_pago_perceptor',
                           when(df['po_pago_perceptor'].startswith('AIDE ASISTENCIA'), 'AIDE ASISTENCIA').otherwise(
                               df['po_pago_perceptor']))

        if self._is_diario:
            df = df.join(aux_perceptor, on='po_pago_perceptor', how='left')
            df = df.join(aux_servicios.drop('id_siniestro'), on='po_gasto_perceptor', how='left')
            for col in list(aux_perceptor.columns) + list(aux_servicios.columns):
                if col not in ['po_pago_perceptor', 'po_gasto_perceptor']:
                    df = df.fillna({col: 0})
            del aux_perceptor
            del aux_servicios

        else:
            # TABLA DE PERCEPTOR
            df.withColumn('po_pago_perceptor',
                          when(df['po_pago_perceptor'].isin([0, '0']), None).otherwise(df['po_pago_perceptor']))
            w_perceptor = (Window().partitionBy('po_pago_perceptor').rowsBetween(-sys.maxsize, sys.maxsize))

            # Por Pagos
            df = df.withColumn('pondera_perceptor', when(df['po_pago_perceptor'].isNotNull(), 1).otherwise(0))
            df = df.withColumn('po_pagos_total_countxperceptor', sum_(df['pondera_perceptor']).over(w_perceptor))
            df = df.drop('pondera_perceptor')

            # Pago anulación
            df = df.fillna({'po_pago_es_anulacion': 0})
            df = df.withColumn('po_pago_es_anulacion_countxperceptor',
                               sum_(df['po_pago_es_anulacion'].cast(IntegerType())).over(w_perceptor))
            df = df.drop('po_pago_es_anulacion')

            variable_float_perceptor = ['po_pago_factura_importe_neto', 'po_pago_indemnizacion_importe_neto']
            # Nota: está bien que haya valores negativos porque son los recobros a otras empresas
            for col in variable_float_perceptor:
                name = col + '_countxperceptor'
                df = df.withColumn(name, sum_(df[col].cast(FloatType())).over(w_perceptor))
                df = df.drop(col)

            # Count a nivel siniestro
            df = df.withColumn('po_pagoxsiniestro_countxperceptor',
                               size(collect_set(df['id_siniestro']).over(w_perceptor)))

            # Obtenemos los niveles promedio por Perceptor-Siniestro
            for col in ['po_pago_factura_importe_neto_countxperceptor',
                        'po_pago_indemnizacion_importe_neto_countxperceptor']:
                df = df.withColumn(col + 'xpromediosiniestro', df[col] / df['po_pagoxsiniestro_countxperceptor'])

            # Perceptor Aparece en blacklist y cuántas
            # FUE UN SINIESTRO FRAUDULENTO? We check if the id_siniestro is associated with a previous Fraud Sinister
            bl_processed = bl_processed.select('id_siniestro').dropDuplicates(subset=['id_siniestro'])
            bl_processed = bl_processed.withColumn('po_reserva_perceptor_fraud', lit(1))
            df = df.join(bl_processed, on='id_siniestro', how='left')
            df = df.withColumn('po_reserva_perceptor_fraud',
                               when(df['po_reserva_perceptor_fraud'].isNull(), 0).otherwise(
                                   df['po_reserva_perceptor_fraud']))

            perc_aux = df.select(['po_pago_perceptor', 'id_siniestro', 'po_reserva_perceptor_fraud']).dropDuplicates(
                subset=['po_pago_perceptor', 'id_siniestro'])
            perc_aux = perc_aux.groupBy('po_pago_perceptor').agg(
                sum_('po_reserva_perceptor_fraud').alias('po_fraude_countxperceptor'))
            df = df.join(perc_aux, on='po_pago_perceptor', how='left')
            del perc_aux

            df = df.withColumn('po_fraude_porcentaje_perceptor',
                               df['po_fraude_countxperceptor'] / df['po_pagoxsiniestro_countxperceptor'])

            df.select(['po_pago_perceptor', 'po_pagos_total_countxperceptor', 'po_pago_es_anulacion_countxperceptor',
                       'po_pago_factura_importe_neto_countxperceptor',
                       'po_pago_indemnizacion_importe_neto_countxperceptor', 'po_pagoxsiniestro_countxperceptor',
                       'po_pago_factura_importe_neto_countxperceptorxpromediosiniestro',
                       'po_pago_indemnizacion_importe_neto_countxperceptorxpromediosiniestro',
                       'po_fraude_countxperceptor', 'po_fraude_porcentaje_perceptor']
                      ).dropDuplicates(subset=['po_pago_perceptor']).coalesce(1).write.mode("overwrite").option(
                "header", "true").option("sep", ";").csv(STRING.training_auxiliar_perceptor)

            # TABLA DE SERVICIOS
            df = df.withColumn('po_gasto_perceptor',
                               when(df['po_gasto_perceptor'].isin([0, '0']), None).otherwise(df['po_gasto_perceptor']))
            w_servicio = (Window().partitionBy('po_gasto_perceptor').rowsBetween(-sys.maxsize, sys.maxsize))

            # Por Pagos
            df = df.withColumn('pondera_servicio', when(df['po_gasto_perceptor'].isNotNull(), 1).otherwise(0))
            df = df.withColumn('po_pagos_total_countxservicios', sum_(df['pondera_servicio']).over(w_servicio))
            df = df.drop('pondera_servicio')

            variable_float_servicio = ['po_gasto_factura_importe_neto', 'po_gasto_indemnizacion_importe_neto']
            # Nota: está bien que haya valores negativos porque son los recobros a otras empresas
            for col in variable_float_servicio:
                name = col + '_countxservicios'
                df = df.withColumn(name, sum_(df[col].cast(FloatType())).over(w_servicio))
                df = df.drop(col)

            # Count a nivel siniestro
            df = df.withColumn('po_pagoxsiniestro_countxservicios',
                               size(collect_set(df['id_siniestro']).over(w_servicio)))

            # Obtenemos el promedio global por Servicio
            for col in ['po_gasto_factura_importe_neto_countxservicios',
                        'po_gasto_indemnizacion_importe_neto_countxservicios']:
                df = df.withColumn(col + 'xpromediosiniestro', df[col] / df['po_pagoxsiniestro_countxservicios'])

            # Perceptor Aparece en blacklist y cuántas
            # FUE UN SINIESTRO FRAUDULENTO? We check if the id_siniestro is associated with a previous Fraud Sinister
            bl_processed = bl_processed.withColumn('po_reserva_servicios_fraud', lit(1))
            df = df.join(bl_processed[['id_siniestro', 'po_reserva_servicios_fraud']], on='id_siniestro', how='left')
            df = df.withColumn('po_reserva_servicios_fraud',
                               when(df['po_reserva_servicios_fraud'].isNull(), 0).otherwise(
                                   df['po_reserva_servicios_fraud']))
            del bl_processed

            serv_aux = df.select(['po_gasto_perceptor', 'id_siniestro', 'po_reserva_servicios_fraud']).dropDuplicates(
                subset=['po_gasto_perceptor', 'id_siniestro'])
            serv_aux = serv_aux.groupBy('po_gasto_perceptor').agg(
                sum_('po_reserva_servicios_fraud').alias('po_fraude_countxservicios'))
            df = df.join(serv_aux, on='po_gasto_perceptor', how='left')
            del serv_aux

            df = df.withColumn('po_fraude_porcentaje_servicios',
                               df['po_fraude_countxservicios'] / df['po_pagoxsiniestro_countxservicios'])

            df.select(['po_gasto_perceptor', 'id_siniestro', 'po_pagos_total_countxservicios',
                       'po_gasto_factura_importe_neto_countxservicios',
                       'po_gasto_indemnizacion_importe_neto_countxservicios', 'po_pagoxsiniestro_countxservicios',
                       'po_gasto_factura_importe_neto_countxserviciosxpromediosiniestro',
                       'po_gasto_indemnizacion_importe_neto_countxserviciosxpromediosiniestro',
                       'po_fraude_countxservicios', 'po_fraude_porcentaje_servicios']
                      ).dropDuplicates(subset=['po_gasto_perceptor']).coalesce(1).write.mode("overwrite").option(
                "header", "true").option("sep", ";").csv(STRING.training_auxiliar_servicios)


        df = df.drop(*['po_pago_perceptor', 'po_gasto_perceptor'])
        df = df.dropDuplicates(subset=['id_siniestro'])
        df = df.fillna({'po_fraude_countxservicios': 0, 'po_fraude_porcentaje_servicios': 0})

        if self._is_diario:
            df_processed = df_processed.select(int_outliers + float_outliers)
            for col in int_outliers + float_outliers:
                df = outliers.Outliers.outliers_test_values(df, df_processed, col, not_count_zero=True)
        else:
            for col in int_outliers + float_outliers:
                df = outliers.Outliers.outliers_mad(df, col, not_count_zero=True)

        # DELETE VARIABLES
        del_variables = ['id_poliza', 'version_poliza', "po_res_garantia_id",
                         "po_res_cobertura_id", 'po_res_limite',
                         "po_pago_IBAN", "po_pago_emision", "po_pago_factura_fecha_emision",
                         'po_pago_factura_importe_neto', 'po_pago_indemnizacion_importe_neto',
                         'po_gasto_IBAN', 'po_gasto_emision', 'po_gasto_factura_fecha_emision',
                         'po_pago_es_anulacion', 'po_gasto_es_anulacion', 'pondera_siniestro',
                         'po_gasto_perceptor', 'po_gasto_factura_importe_neto', 'po_gasto_indemnizacion_importe_neto',
                         'po_pago_importe_neto', 'po_gasto_importe_neto',
                         'po_pago_importe_neto_ASEGURADO', 'po_pago_importe_porcentual_ASEGURADO',
                         'audit_poliza_producto_tecnico',
                         'audit_siniestro_codigo_compania', 'po_reserva_indemxsiniestro_count'
                         ]

        df = df.drop(*del_variables)

        return df