Как создать цикл для итерации соединения с pyspark - PullRequest
1 голос
/ 02 ноября 2019

Я работаю над Databricks, и у меня есть фрейм данных, который содержит список спецификации (спецификация): структура фрейма данных представлена ​​в следующем примере, где идентификатором является код продукта «папа» (готовый продукт), а компонент - это код «сына» продукта (который может быть полуфабрикатом или сырьем). Если компонент является полуфабрикатом, его также можно найти в списке идентификаторов с его компонентами (но в кадре данных нет указания, указывающего тип продукта: готовый, полуфабрикатный или сырой).

  identifier   component
  xxxx         yyyy
  xxxx         zzzz
  xxxx         aaaa
  aaaa         bbbb
  aaaa         cccc
  bbbb         dddd
  bbbb         eeee
  cccc         ffff
  cccc         mmmm
  ffff         aaaa
  ffff         gggg
  ffff         hhhh
  hhhh         iiii
  hhhh         jjjj

В приведенном выше примере есть два конечных продукта (xxxx и ffff). XXXX имеет в качестве компонентов yyyy, zzzz и aaaa. aaaa должен быть полуфабрикатом, поскольку он также указан в столбце идентификатора и состоит из cccc и dddd. cccc и dddd также являются полуфабрикатами, поскольку они перечислены в столбце идентификатора и состоят из dddd, eeee, ffff и mmmm (которые должны быть исходными материалами, поскольку их нет в столбце идентификатора). Второй конечный продукт ffff состоит из aaaa (полуфабрикат, также используемый для xxxx), gggg (сырье) и hhhh (полуфабрикат, состоящий из iiii и jjjj, сырья). Я должен отфильтровать этот фрейм данных по списку продуктов, предоставленных мной по бизнесу, который содержит только конечные продукты: предположим, что мне нужно выбрать только xxxx (ffff отсутствует в списке). Проблема в том, что если я отфильтрую xxxx, я потеряю информацию, связанную с полуфабрикатами (если я отфильтрую кадр данных, выбрав только идентификатор xxxx, я получу 3 строки, но мне нужно найти способ сохранить также aaaa,bbbb и cccc, и для каждого из них также детали их компонентов). Таким образом, окончательный отфильтрованный кадр данных должен быть

    identifier   component
  xxxx         yyyy
  xxxx         zzzz
  xxxx         aaaa
  aaaa         bbbb
  aaaa         cccc
  bbbb         dddd
  bbbb         eeee
  cccc         ffff
  cccc         mmmm

Я пытаюсь выяснить, как решить эту проблему с помощью цикла (реальный кадр данных явно больше, примерно 13000 строк), но я не могу найтихорошая отправная точка (я не эксперт по питону). Кто-нибудь в качестве хорошего предложения, документации или фрагмента для использования в качестве отправной точки?

1 Ответ

0 голосов
/ 02 ноября 2019

Если я отфильтрую кадр данных, выбрав только идентификатор xxxx, я получу 3 строки, но мне нужно найти способ сохранить также aaaa, bbbb и cccc

Разве вы не имеете в виду, вы должны найти способ сохранить yyyy, zzzz и aaaa, так как от этих продуктов зависит xxxx? Проясните это и объясните немного больше о том, как вы получаете окончательный отфильтрованный кадр данных (я получаю другой результат), и я буду рад помочь.

Я все ещерад помочь, но я все еще не понимаю, как вы пришли к своему окончательному отфильтрованному фрейму данных.

Итак, вы выбираете xxxx и получаете три связанных компонента yyyy, zzzz и aaaa. Тогда что? Вы получаете связанные компоненты для этих трех компонентов и делаете это рекурсивно, пока не получите базовые материалы? Это не отражает того, что находится в вашем последнем отфильтрованном фрейме данных.

РЕДАКТИРОВАТЬ Если я правильно понимаю вопрос, вот что я придумала (я не пользуюсь пандами регулярно, поэтому я не удивлюсь, если есть функции панд, которые могли бы сделать этот кутер):

def main():

    import pandas as pd
    from queue import Queue

    df = pd.read_csv("data.csv", names=["identifier", "component"])

    result_df = pd.DataFrame()

    selected_identifier = "xxxx"
    identifier_queue = Queue()
    identifier_queue.put(selected_identifier)
    previously_seen_identifiers = set()

    while not identifier_queue.empty():
        current_identifier = identifier_queue.get()
        if current_identifier in previously_seen_identifiers:
            continue
        previously_seen_identifiers.add(current_identifier)
        current_df = df.loc[df["identifier"] == current_identifier]
        result_df = result_df.append(current_df)
        components = current_df[["component"]]["component"].tolist()
        for component in components:
            identifier_queue.put(component)

    print(result_df)

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

Вот как это работает:

  • Создать очередь (это также можетбыть стеком) идентификаторов, которые все еще должны быть обработаны. Первоначально единственный идентификатор для обработки конечного продукта, который мы выбираем (xxxx в данном случае).
  • Пока очередь не пуста, получите следующий идентификатор и удалите его из очереди, создайте кадр данных изисходный кадр данных, содержащий только компоненты, от которых зависит текущий идентификатор, и добавьте этот субкадр в кадр данных result_df. Прежде чем мы начнем следующую итерацию, мы возьмем связанные компоненты, от которых зависит текущий идентификатор, и добавим их в нашу очередь необработанных идентификаторов.
  • Перед циклом мы также создали set() для отслеживания всехидентификаторы, которые мы видели до сих пор. В цикле, если текущий идентификатор уже был просмотрен, мы игнорируем его и переходим к следующему идентификатору. Это было сделано потому, что некоторые продукты имеют круговую зависимость.

Дайте мне знать, если вы об этом думаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...