Extrair valores de uma matriz que soma a um determinado valor pyspark

0

Pergunta

Eu tenho uma dataframe que tem uma matriz com duplas como valores. Dentro da matriz, 1 ou uma soma dos números é igual a um determinado valor de destino, e eu quero extrair os valores de que ou igual ao valor ou pode ser somadas para o valor. Eu gostaria de ser capaz de fazer isso em 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

Melhor resposta

1

Você pode encapsular a lógica de como uma udf e criar NewArray com base nesta. Tenho emprestado a lógica para identificar os elementos de matriz de soma de um valor-alvo a partir de aqui.


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)

Saída

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

Obrigado por sua ajuda, é definitivamente me colocar no caminho certo. No entanto, eu estou tendo problemas neste ponto: se s >= destino: troca eu recebo um erro quando deixado em: TypeError: '>=' não suportado entre instâncias de 'int' e 'NoneType'. Quando eu tirar isso ele é executado, mas ele não retornar todos os valores que soma para o alvo, só mostra quando 1 dos valores é igual ao destino por si só.
Alex Triece

Além disso, o problema poderia ser que as casas decimais que eu estou usando são bem menores (no .0031 e .0001 gama). Eu notei que quando eu substituído os dados de exemplo com números decimais como este voltou vazia matrizes. Quaisquer pensamentos sobre isso?
Alex Triece

Para o primeiro problema, eu acho que você não tem Nenhuns valores em target coluna. Para isso vou atualizar as respostas para retornar uma matriz vazia se isso acontecer.
Nithish

Você estava absolutamente certo sobre o primeiro problema. Mudou o na s a 0 e ele funciona muito bem. No entanto, ele não lê o menor casas decimais. Eu estou ok com 0 na coluna de destino, assim não há necessidade de gastar muito tempo com esse problema, a menos que você deseja para que outros o amor de deus.
Alex Triece

O código a resposta é agora na ou null cofre. Para a precisão, eu precisaria de um exemplo, eu tentei por intervalos menores demasiado 6 dígitos decimais e ele ainda funciona. Um exemplo poderá ajudar a replicar.
Nithish

Apenas mudou o topo exemplo para mostrar que eu estou olhando, na verdade, apenas a primeira linha. Quando eu ligar este, para eu obter resultados corretos para tudo, exceto a linha superior.
Alex Triece

O problema é devido ao ponto flutuante de precisão de erro, em Python 0.0001 + 0.0031 é 0.0031999999999999997 stackoverflow.com/questions/11950819/python-math-is-wrong/..., eu atualizei a resposta para suporte a aritmética de precisão para apoiar o seu caso de uso.
Nithish

Obrigado, isso ajuda. No entanto, ele gera um erro com o Decimal() função. Há algo que precisa ser importada para que seja reconhecido?
Alex Triece

Em outros idiomas

Esta página está em outros idiomas

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