Wyjmij wartości z tablicy, które sumują się z określoną wartością pyspark

0

Pytanie

Mam ramkę danych, który zawiera tablicę z dwoma wartościami. W tablicy 1 lub suma liczb jest równa określonej wartości docelowej, i chcę wyodrębnić wartości, które są albo równe wartości, albo mogą się łączyć, aby być równa wartości. Chciałbym mieć możliwość, aby to zrobić w Пыспарке.

| 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

Najlepsza odpowiedź

1

Można hermetyzacji logiki w postaciudf i stworzyć NewArray wychodząc z tego. Pożyczyłem logiki do identyfikacji elementów sumowania macierzy do wartości docelowej stąd.


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)

Wyjście

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

Dziękuję za pomoc, to na pewno prowadzi mnie na właściwą drogę. Jednak w tej chwili mam problemy: jeśli s >= cel: powrót, pojawia się błąd przy pozostawieniu w: Błąd typu: '>>=' nie jest obsługiwany między wystąpieniami 'int' i 'NoneType'. Kiedy wyjmuję to, to uruchamia się, ale nie zwraca wszystkie wartości, które sumują się z celem, pokazuje tylko, gdy 1 z wartości samo w sobie jest równa cele.
Alex Triece

Ponadto, problem może leżeć w tym, że dziesiętne, które używam, znacznie mniej (w zakresie .0031 i .0001). Zauważyłem, że gdy wymieniłem dane przykład miejscami po przecinku, jak to jest, oddał puste tablice. Masz jakieś przemyślenia na ten temat?
Alex Triece

Co do pierwszego pytania, myślę, że nie ma żadnych wartości w target kolumna. Do tego mogę zaktualizować odpowiedzi, aby oddać pustą tablicę, jeśli to się stanie.
Nithish

Miałeś całkowitą rację w tym pierwszym pytaniu. Zmieniłem na 0, i to działa dobrze. Jednak on nie czyta mniejsze ułamki dziesiętne. Zgadzam się z 0 w wybranej kolumnie, więc nie trzeba tracić zbyt wiele czasu na ten problem, jeśli tylko nie chcesz tego dla innych.
Alex Triece

Kod odpowiedzialny teraz na lub null bezpieczny. Dla ścisłości trzeba mi przykład, próbowałem dla mniejszych zakresów też do 6 cyfr po przecinku, i to wszystko jeszcze działa. Przykład pomógł by odtworzyć.
Nithish

Po prostu zmienił górny przykład, aby pokazać, na co patrzę, właściwie tylko pierwszy szereg. Gdy łączę to, mam poprawne wyniki dla wszystkich, z wyjątkiem górnego wiersza.
Alex Triece

Problem jest związany z błędem dokładności zmiennoprzecinkowych w Pythonie 0.0001 + 0.0031 jest 0.0031999999999999997 stackoverflow.com/questions/11950819/python-math-is-wrong/..., zaktualizowałem odpowiedzi do obsługi dokładne arytmetyki, aby wspierać swoje zastosowanie.
Nithish

Dziękuję, to pomaga. Jednak to prowadzi do błędu z funkcją Decimal (). Czy jest coś, co chcesz zaimportować, aby to było rozpoznane?
Alex Triece

W innych językach

Ta strona jest w innych językach

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