Объединение нескольких фреймов данных построчно в 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фреймов в один фрейм данных, как мне это сделать?

Я уже пробовал с 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-кратного резюме. Вот что я сделаю: порции = [0,1] * 10 cv = df7.randomSplit (порции) folds = список (range (10)) для i в range (10): test_data = cv [i] fold_no_i = folds [: i] + folds [i + 1:] train_data = cv [fold_no_i [0]] для j в fold_no_i [1:]: train_data = train_data.union (cv [j])
ngoc thoag

Ответы:


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.

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


(+1) Хороший обходной путь. Однако должна существовать функция, которая позволяет объединять несколько фреймов данных. Было бы очень удобно!
Dawny33

Я не согласен с этим
Ян ван дер Вегт

@JanvanderVegt Спасибо, это работает, и идея добавления меток для фильтрации набора данных для обучения и тестирования, я уже сделал это. Спасибо большое за помощь.
Кришна Прасад

@Jan van der Vegt Можете ли вы применить ту же логику для Присоединиться и ответить на этот вопрос
GeorgeOfTheRF


6

Иногда, когда объединяемые кадры данных не имеют одинаковый порядок столбцов, лучше использовать df2.select (df1.columns), чтобы оба объединения имели одинаковый порядок столбцов перед объединением.

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.