web-dev-qa-db-fra.com

TypeError: a obtenu un argument de mot clé inattendu

Le code apparemment simple ci-dessous génère l'erreur suivante:

Traceback (most recent call last):
  File "/home/nirmal/process.py", line 165, in <module>
    'time_diff': f.last(adf['time_diff']).over(window_device_rows)
TypeError: __call__() got an unexpected keyword argument 'this_campaign'

Code:

# Function to flag network timeouts
def flag_network_timeout(**kwargs):
    if kwargs['this_network'] != kwargs['last_network'] \
            or kwargs['this_campaign'] != kwargs['last_campaign'] \
            or kwargs['this_adgroup'] != kwargs['last_adgroup'] \
            or kwargs['this_creative'] != kwargs['last_creative'] \
            or kwargs['time_diff'] > network_timeout:
        return 1
    else:
        return 0
flag_network_timeout = f.udf(flag_network_timeout, IntegerType())

# Column spec to go over the device events and flag network resets
network_timeout_flag = flag_network_timeout(**{
    'last_network': f.first(adf['network']).over(window_device_rows),
    'last_campaign': f.first(adf['campaign']).over(window_device_rows),
    'last_adgroup': f.first(adf['adgroup']).over(window_device_rows),
    'last_creative': f.first(adf['creative']).over(window_device_rows),
    'this_network': f.last(adf['network']).over(window_device_rows),
    'this_campaign': f.last(adf['campaign']).over(window_device_rows),
    'this_adgroup': f.last(adf['adgroup']).over(window_device_rows),
    'this_creative': f.last(adf['creative']).over(window_device_rows),
    'time_diff': f.last(adf['time_diff']).over(window_device_rows)
})

# Update dataframe with the new columns
adf = adf.select('*', network_timeout_flag.alias('network_timeout'))

Qu'est-ce que je fais mal s'il vous plait? Je vous remercie.

8
Nirmal

Vous obtenez une exception car UserDefinedFunction.__call__ ne prend en charge que les varargs et non les arguments de mots clés.

def __call__(self, *cols):
    sc = SparkContext._active_spark_context
    jc = self._judf.apply(_to_seq(sc, cols, _to_Java_column))
    return Column(jc)

A un niveau beaucoup plus basique, UDF ne peut recevoir que des arguments Column, qui seront développés à leur valeur correspondante lors de l'exécution, et non des objets standard Python.

Personnellement, je n'utiliserais pas **kwargs pour cela, mais en ignorant que vous pouvez réaliser ce que vous voulez en composant des expressions SQL:

def flag_network_timeout_(**kwargs):

    cond = (
        (kwargs['this_network'] != kwargs['last_network']) |
        (kwargs['this_campaign'] != kwargs['last_campaign']) |
        (kwargs['this_adgroup'] != kwargs['last_adgroup']) |
        (kwargs['this_creative'] != kwargs['last_creative']) |
        (kwargs['time_diff'] > network_timeout))

    return f.when(cond, 1).otherwise(0)
12
zero323