Estrarre i valori da una matrice che la somma di un certo valore pyspark

0

Domanda

Ho un dataframe che ha una matrice con doppie come valori. All'interno della matrice, 1 o la somma dei numeri è uguale a un certo valore di destinazione, e voglio estrarre i valori che sia uguale il valore o può essere una somma pari al valore. Mi piacerebbe essere in grado di fare questo in PySpark.

| Array                  | Target    | NewArray         |
| -----------------------|-----------|------------------|
| [0.0001,2.5,3.0,0.0031]| 0.0032    | [0.0001,0.0031]  |
| [2.5,1.0,0.5,3.0]      | 3.0       | [2.5, 0.5, 3.0]  |
| [1.0,1.0,1.5,1.0]      | 4.5       | [1.0,1.0,1.5,1.0]|
arrays extract pyspark sum
2021-11-23 19:39:03
1

Migliore risposta

1

È possibile incapsulare la logica di un udf e creare NewArray su questa base. Ho preso in prestito la logica per l'identificazione degli elementi di matrice somma di un valore target da qui.


from pyspark.sql.types import ArrayType, DoubleType
from pyspark.sql.functions import udf
from decimal import Decimal

data = [([0.0001,2.5,3.0,0.0031], 0.0032),
([2.5, 1.0, 0.5, 3.0], 3.0),
([1.0, 1.0, 1.5, 1.0], 4.5), 
([], 1.0),
(None, 1.0),
([1.0,2.0], None),]


df = spark.createDataFrame(data, ("Array", "Target", ))


@udf(returnType=ArrayType(DoubleType()))
def find_values_summing_to_target(array, target):
    def subset_sum(numbers, target, partial, result):
        s = sum(partial)
        # check if the partial sum is equals to target
        if s == target: 
            result.extend(partial)
        if s >= target:
            return  # if we reach the number why bother to continue
    
        for i in range(len(numbers)):
            n = numbers[i]
            remaining = numbers[i+1:]
            subset_sum(remaining, target, partial + [n], result)
    result = []
    if array is not None and target is not None:
        array = [Decimal(str(a)) for a in array]
        subset_sum(array, Decimal(str(target)), [], result)
        result = [float(r) for r in result]
    return result

df.withColumn("NewArray", find_values_summing_to_target("Array", "Target")).show(200, False)

Uscita

+--------------------------+------+--------------------+
|Array                     |Target|NewArray            |
+--------------------------+------+--------------------+
|[1.0E-4, 2.5, 3.0, 0.0031]|0.0032|[1.0E-4, 0.0031]    |
|[2.5, 1.0, 0.5, 3.0]      |3.0   |[2.5, 0.5, 3.0]     |
|[1.0, 1.0, 1.5, 1.0]      |4.5   |[1.0, 1.0, 1.5, 1.0]|
|[]                        |1.0   |[]                  |
|null                      |1.0   |[]                  |
|[1.0, 2.0]                |null  |[]                  |
+--------------------------+------+--------------------+
2021-11-29 17:22:52

Grazie per il vostro aiuto, è sicuramente avermi messo sulla strada giusta. Tuttavia sto avendo problemi a questo punto: se s >= target: ritorno ricevo un errore quando a sinistra in: TypeError: '>=' non supportato tra le istanze di 'int' e 'NoneType'. Quando prendo questo funziona, ma non restituisce tutti i valori che si somma a destinazione, si vede solo quando 1 dei valori è pari a destinazione di per sé.
Alex Triece

Inoltre, il problema potrebbe essere che le cifre decimali che sto usando sono molto più piccoli (in .0031 e .0001 gamma). Ho notato che quando ho sostituito i dati di esempio con cifre decimali come questo è di ritorno a vuoto matrici. Ogni pensiero su che?
Alex Triece

Per il primo problema, penso che tu abbia Nessuno valori in target colonna. Per questo voglio aggiornare le risposte a restituire un array vuoto, se questo accade.
Nithish

Vi erano assolutamente ragione su questo primo numero. Cambiato il na a 0 e funziona benissimo. Tuttavia, non leggere il più piccolo decimali. Io sono ok con 0 nella colonna di destinazione, quindi non c'è bisogno di spendere troppo tempo su questo problema, a meno che non si desidera per altri motivi.
Alex Triece

Il codice di risposta è ora na o null cassetta di sicurezza. Per la precisione avrei bisogno di un esempio, ho provato per piccoli intervalli di troppo 6 cifre decimali e funziona ancora. Un esempio potrebbe aiutare a replicare.
Nithish

Appena cambiato l'alto esempio per mostrare che cosa sto guardando, in realtà solo la prima riga. Quando ho questo plug in, ho ottenere risultati corretti per tutto, tranne la riga superiore.
Alex Triece

Il problema è dovuto alla precisione in virgola mobile di errore, in Python 0.0001 + 0.0031 è 0.0031999999999999997 stackoverflow.com/questions/11950819/python-math-is-wrong/..., ho aggiornato la risposta a sostenere aritmetica a precisione per sostenere il vostro caso d'uso.
Nithish

Grazie, il che aiuta. Tuttavia, si genera un errore con il separatore Decimale() funzione. C'è qualcosa che deve essere importato che, per essere riconosciuto?
Alex Triece

In altre lingue

Questa pagina è in altre lingue

Русский
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................