Извлеките значения из массива, которые суммируются с определенным значением pyspark

0

Вопрос

У меня есть фрейм данных, содержащий массив с двойными значениями. В массиве 1 или сумма чисел равна определенному целевому значению, и я хочу извлечь значения, которые либо равны значению, либо могут быть суммированы, чтобы равняться значению. Я бы хотел иметь возможность сделать это в Пыспарке.

| 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

Лучший ответ

1

Вы можете инкапсулировать логику в видеudf и создать NewArray исходя из этого. Я позаимствовал логику для идентификации элементов суммирования массива до целевого значения отсюда.


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)

Выход

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

Спасибо за вашу помощь, это определенно наставляет меня на правильный путь. Однако на данный момент у меня возникли проблемы: если s >= цель: возврат, я получаю ошибку при оставлении в: Ошибка типа: '>>=' не поддерживается между экземплярами 'int' и 'NoneType'. Когда я вынимаю это, оно запускается, но не возвращает все значения, которые суммируются с целью, показывает только, когда 1 из значений само по себе равно цели.
Alex Triece

Кроме того, проблема может заключаться в том, что десятичные дроби, которые я использую, намного меньше (в диапазоне .0031 и .0001). Я заметил, что, когда я заменил данные примера десятичными знаками, как это, он вернул пустые массивы. Есть какие-нибудь мысли по этому поводу?
Alex Triece

Что касается первого вопроса, я думаю, что у вас нет никаких ценностей в target колонка. Для этого я обновлю ответы, чтобы вернуть пустой массив, если это произойдет.
Nithish

Вы были абсолютно правы в том первом вопросе. Изменил na на 0, и это работает нормально. Однако он не считывает меньшие десятичные дроби. Я согласен с 0 в целевом столбце, поэтому не нужно тратить слишком много времени на эту проблему, если только вы не хотите этого ради других.
Alex Triece

Код в ответе теперь na или null безопасный. Для точности мне понадобится пример, я попробовал для меньших диапазонов тоже 6 десятичных цифр, и это все еще работает. Пример помог бы воспроизвести.
Nithish

Просто изменил верхний пример, чтобы показать, на что я смотрю, на самом деле только первый ряд. Когда я подключаю это, я получаю правильные результаты для всего, кроме верхней строки.
Alex Triece

Проблема связана с ошибкой точности с плавающей запятой в Python 0.0001 + 0.0031 является 0.0031999999999999997 stackoverflow.com/questions/11950819/python-math-is-wrong/..., я обновил ответ для поддержки точной арифметики, чтобы поддержать ваше использование.
Nithish

Спасибо, это помогает. Однако это приводит к ошибке с функцией Decimal (). Есть ли что-то, что нужно импортировать, чтобы это было распознано?
Alex Triece

На других языках

Эта страница на других языках

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

Популярное в этой категории

Популярные вопросы в этой категории