Extraer valores de una matriz que se suma a un cierto valor pyspark

0

Pregunta

Tengo un dataframe que tiene una matriz con los dobles de los valores. Dentro de la matriz, 1 o suma de los números es igual a un cierto valor objetivo, y quiero extraer los valores que igual el valor o puede ser resumido a la igualdad de valor. Me gustaría ser capaz de hacer esto en 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

Mejor respuesta

1

Usted puede encapsular la lógica como una udf y crear NewArray basado en esto. He tomado la lógica para la identificación de los elementos de la matriz de sumar a un valor objetivo a partir de aquí.


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)

Salida

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

Gracias por tu ayuda, definitivamente me pone en la pista de la derecha. Sin embargo estoy teniendo problemas en este punto: si s >= objetivo: volver me sale un error cuando la izquierda en: TypeError: '>=' no se admite entre las instancias de 'int' y 'NoneType'. Cuando me tome esto se ejecuta, pero no se devuelve todos los valores que se suma a la de destino, sólo se muestra cuando 1 de los valores es igual a la de destino por sí mismo.
Alex Triece

Además, el problema podría ser que los decimales estoy usando son mucho más pequeños (en el .0031 y .0001 gama). Me di cuenta que cuando lo he sustituido el ejemplo de datos con decimales como este se devuelven matrices vacías. Alguna idea sobre que?
Alex Triece

Para la primera cuestión, creo que usted no tiene Ninguno de los valores en target columna. Para esto voy a actualizar las respuestas a devolver un array vacío si esto sucede.
Nithish

Ustedes tenían razón acerca de que la primera edición. Cambiado el na a 0 y funciona bien. Sin embargo, no leer los más pequeños decimales. Yo estoy bien con 0 en la columna de destino, por lo que no hay necesidad de gastar demasiado tiempo en esa cuestión, a menos que usted desea para los demás' bien.
Alex Triece

El código de la respuesta es ahora na o null seguro. Para la precisión que iba a necesitar un ejemplo, he intentado durante intervalos más pequeños también 6 dígitos decimales y todavía funciona. Un ejemplo podría ayudar a replicar.
Nithish

Sólo se ha cambiado la parte superior de ejemplo para mostrar lo que estoy mirando, en realidad sólo la primera fila. Cuando me conecte esta, yo obtener los resultados correctos para todo, excepto la fila superior.
Alex Triece

El problema es debido a de punto flotante de precisión error, en Python 0.0001 + 0.0031 es 0.0031999999999999997 stackoverflow.com/questions/11950819/python-math-is-wrong/..., he actualizado la respuesta para apoyar la aritmética de precisión para apoyar su caso de uso.
Nithish

Gracias, eso ayuda. Sin embargo, se produce un error con el Decimal() función. Hay algo que necesita ser importado para que sea reconocido?
Alex Triece

En otros idiomas

Esta página está en otros idiomas

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