Extraire des valeurs d'un tableau qui résume à une certaine valeur pyspark

0

La question

J'ai un dataframe qui a un tableau avec des doubles comme des valeurs. Dans la matrice, 1 ou une somme des chiffres est égale à une certaine valeur de la cible, et je veux extraire les valeurs que soit égale à la valeur ou peut être résumé à l'égalité de la valeur. J'aimerais être capable de le faire dans 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

La meilleure réponse

1

Vous pouvez encapsuler la logique comme une udf et créer NewArray sur cette base. J'ai emprunté la logique de l'identification des éléments de tableau résumant à une valeur cible à partir d' ici.


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)

Sortie

+--------------------------+------+--------------------+
|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

Merci pour votre aide, c'est vraiment de me mettre sur la bonne voie. Cependant, je vais avoir de la difficulté à ce stade: si s >= cible: retour j'obtiens une erreur lors de la gauche dans: TypeError: '>=' pas de prise en charge entre les instances de 'int' et 'NoneType'. Quand je prends ce qu'il s'exécute, mais il ne veut pas retourner toutes les valeurs que la somme de la cible, ne montre que lorsque 1 des valeurs est égale à la cible par lui-même.
Alex Triece

En outre, le problème pourrait être que le nombre de décimales que j'utilise sont beaucoup plus petits (dans le .0031 et .0001 gamme). J'ai remarqué lorsque j'ai remplacé l'exemple de données avec des décimales comme cela, il est retourné tableaux vides. Des idées à ce sujet?
Alex Triece

Pour la première question, je pense que vous n'en avez pas les valeurs dans target la colonne. Pour cela, je vais mettre à jour les réponses à retourner un tableau vide si cela se produit.
Nithish

Vous étiez tout à fait raison à propos de cette première question. Changé la de na à 0 et il fonctionne très bien. Cependant, il ne lit pas les petites décimales. Je suis ok avec des 0 dans la colonne cible, donc pas besoin de passer trop de temps sur cette question, sauf si vous voulez pour les autres, l'amour.
Alex Triece

Le code de la réponse est maintenant na ou null coffre-fort. Pour la précision, j'aurais besoin d'un exemple, j'ai essayé pour les petites plages de trop 6 chiffres après la virgule et il fonctionne toujours. Par exemple, contribuent à reproduire.
Nithish

Juste changé le haut exemple pour montrer ce que je suis en train de regarder, vraiment juste la première ligne. Lorsque je branche ce, j'obtiens des résultats corrects pour tout sauf la ligne du haut.
Alex Triece

Le problème est dû à la précision en virgule flottante d'erreur, en Python 0.0001 + 0.0031 est 0.0031999999999999997 stackoverflow.com/questions/11950819/python-math-is-wrong/..., j'ai mis à jour la réponse à l'appui de la précision arithmétique à l'appui de votre cas d'utilisation.
Nithish

Merci, ça aide. Cependant, il renvoie une erreur avec la Virgule() fonction. Est-il quelque chose qui doit être importé pour être reconnu?
Alex Triece

Dans d'autres langues

Cette page est dans d'autres langues

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