Mesclando vários quadros de dados em linhas no PySpark


21

Eu tenho quadros 10 dados pyspark.sql.dataframe.DataFrame, obtidos a partir randomSplitde (td1, td2, td3, td4, td5, td6, td7, td8, td9, td10) = td.randomSplit([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1], seed = 100)agora eu quero participar 9 tdé em um único quadro de dados, como devo fazer isso?

Eu já tentei com unionAll, mas essa função aceita apenas dois argumentos.

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)

Existe alguma maneira de combinar mais de dois quadros de dados em linhas?

O objetivo é fazer 10 vezes a validação cruzada manualmente, sem usar o CrossValidatormétodo PySpark . Portanto, levo 9 para o treinamento e 1 para os dados de teste e depois repetirei para outras combinações.


1
Isso não responde diretamente à pergunta, mas aqui sugiro melhorar o método de nomeação para que, no final, não tenhamos que digitar, por exemplo: [td1, td2, td3, td4, td5, td6, td7 , td8, td9, td10]. Imagine fazer isso para um CV de 100 vezes. Aqui está o que vou fazer: porções = [0,1] * 10 cv = df7.randomSplit (porções) dobras = lista (intervalo (10)) para i no intervalo (10): test_data = cv [i] fold_no_i = folds [: i] + dobra [i + 1:] train_data = cv [fold_no_i [0]] para j em fold_no_i [1:]: train_data = train_data.union (cv [j])
ngoc thoag

Respostas:


37

Roubado de: /programming/33743978/spark-union-of-multiple-rdds

Fora dos sindicatos em encadeamento, essa é a única maneira de fazê-lo nos 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)

O que acontece é que ele pega todos os objetos que você passou como parâmetros e os reduz usando unionAll (essa redução é do Python, não o Spark, embora eles funcionem da mesma forma), o que eventualmente o reduz a um DataFrame.

Se, em vez dos DataFrames, eles são RDDs normais, você pode passar uma lista deles para a função de união do seu SparkContext

EDIT: Para seu propósito, proponho um método diferente, já que você teria que repetir toda essa união 10 vezes para suas dobras diferentes para validação cruzada, adicionaria rótulos aos quais pertence uma dobra de uma linha e apenas filtraria seu DataFrame para cada dobra com base em o rótulo


(+1) Uma boa solução. No entanto, é preciso haver uma função que permita a concatenação de vários quadros de dados. Seria bastante útil!
Dawny33

Eu não concordo com isso
Jan van der Vegt

@JanvanderVegt Obrigado, funciona e a ideia de adicionar etiquetas para filtrar o conjunto de dados de treinamento e teste, eu já fiz. Muito obrigado pela sua ajuda.
Krishna Prasad

@Jan van der Vegt Você pode aplicar a mesma lógica para Participar e responder a esta pergunta
GeorgeOfTheRF


6

Em algum momento, quando os quadros de dados a serem combinados não tiverem a mesma ordem de colunas, é melhor df2.select (df1.columns) para garantir que ambos os df tenham a mesma ordem de coluna antes da união.

import functools 

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

Exemplo:

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() 

insira a descrição da imagem aqui

caso contrário, geraria o resultado abaixo.

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()

insira a descrição da imagem aqui


2

Que tal usar recursão?

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])
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.