Об’єднання декількох фреймів даних у рядку PySpark


21

У мене є кадри 10 даних pyspark.sql.dataframe.DataFrame, отриманих від , randomSplitяк (td1, td2, td3, td4, td5, td6, td7, td8, td9, td10) = td.randomSplit([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1], seed = 100)зараз , я хочу приєднатися до 9 td«S в один кадр даних, як я повинен робити це?

Я вже пробував unionAll, але ця функція приймає лише два аргументи.

td1_2 = td1.unionAll(td2) 
# this is working fine

td1_2_3 = td1.unionAll(td2, td3) 
# error TypeError: unionAll() takes exactly 2 arguments (3 given)

Чи є якийсь спосіб поєднати більше двох кадрів даних по рядку?

Мета цього полягає в тому, що я роблю 10-кратну перехресну валідацію вручну, не використовуючи CrossValidatorметод PySpark , тому я беру 9 у тренінг і 1 - на тестові дані, а потім повторюю це для інших комбінацій.


1
Це не відповідає безпосередньо на питання, але тут я даю пропозицію вдосконалити метод іменування, щоб врешті-решт нам не довелося вводити, наприклад: [td1, td2, td3, td4, td5, td6, td7 , td8, td9, td10]. Уявіть, що ви робите це для 100-кратного резюме. Ось що я зроблю: portions = [0,1] * 10 cv = df7.randomSplit (порції) folds = список (діапазон (10)) для i в діапазоні (10): test_data = cv [i] fold_no_i = folds [: i] + складки [i + 1:] train_data = cv [fold_no_i [0]] для j в fold_no_i [1:]: train_data = train_data.union (cv [j])
ngoc груд

Відповіді:


37

Викрадено з: /programming/33743978/spark-union-of-multiple-rdds

За межами ланцюжкових спілок це єдиний спосіб зробити це для DataFrames.

from functools import reduce  # For Python 3.x
from pyspark.sql import DataFrame

def unionAll(*dfs):
    return reduce(DataFrame.unionAll, dfs)

unionAll(td2, td3, td4, td5, td6, td7, td8, td9, td10)

Що трапляється, це те, що він приймає всі об'єкти, які ви передали як параметри, і зменшує їх за допомогою UnionAll (це зменшення відбувається від Python, а не Spark зменшення, хоча вони працюють аналогічно), що з часом зменшує його до однієї DataFrame.

Якщо замість DataFrames вони є нормальними RDD, ви можете передати їх список у функцію об'єднання вашого SparkContext

EDIT: Для вашої мети я пропоную інший метод, оскільки вам доведеться повторити весь цей союз 10 разів для ваших різних складок для перехресної перевірки, я би додав мітки, до яких належить рядок, і просто фільтрую ваш DataFrame для кожної складки на основі етикетка


(+1) Приємна робота. Однак повинна бути функція, яка дозволяє об'єднати декілька фреймів даних. Було б досить зручно!
Світанок33

Я з цим не згоден
Ян ван дер Вегт

@JanvanderVegt Дякую, це працює і ідея додавання міток для фільтрації навчальних і тестувальних даних, я це вже робив. Велике спасибі за вашу допомогу.
кришна Прасад

@Jan van der Vegt Чи можете ви застосувати ту саму логіку для
приєднання


6

Коли-небудь, коли рамки даних для комбінування не мають однакового порядку стовпців, краще df2.select (df1.column), щоб переконатися, що обидва df мають однаковий порядок стовпців перед об'єднанням.

import functools 

def unionAll(dfs):
    return functools.reduce(lambda df1,df2: df1.union(df2.select(df1.columns)), dfs) 

Приклад:

df1 = spark.createDataFrame([[1,1],[2,2]],['a','b'])
# different column order. 
df2 = spark.createDataFrame([[3,333],[4,444]],['b','a']) 
df3 = spark.createDataFrame([555,5],[666,6]],['b','a']) 

unioned_df = unionAll([df1, df2, df3])
unioned_df.show() 

введіть тут опис зображення

інакше це створить результат нижче.

from functools import reduce  # For Python 3.x
from pyspark.sql import DataFrame

def unionAll(*dfs):
    return reduce(DataFrame.unionAll, dfs) 

unionAll(*[df1, df2, df3]).show()

введіть тут опис зображення


2

Як щодо використання рекурсії?

def union_all(dfs):
    if len(dfs) > 1:
        return dfs[0].unionAll(union_all(dfs[1:]))
    else:
        return dfs[0]

td = union_all([td1, td2, td3, td4, td5, td6, td7, td8, td9, td10])
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.