Cruzando duas bases enormes com Pandas

Estou tentando cruzar dois bancos de dados enormes. Uma tem 15 milhões de linhas e outra uns 25 milhões. As duas são dataframes em Pandas. No momento, estou dividindo uma das bases (a com 15 milhões) em bases menores (com cerca de 10000 linhas (isso é necessário para a pauta) e depois disso cruzando com a base maior.

Esse cruzamento é feito primeiro transformando as colunas que eu quero cruzar em listas. Depois, cruzo as duas listas com o seguinte comando:

resultados = list(set(lista_maior) & set(lista_menor))

Como é de se imaginar, o processo demora MUITO tempo. Queria a ajuda de vocês para tentar descobrir um jeito que demore menos. Alguém tem alguma ideia de como melhorar esse processo?

1 Curtida

Olá @lucasmarchesini
Este exemplo de script lê os arquivos de sócios que a Receita Federal divulga periodicamente, também com milhões de linhas

Basicamente eu leio o arquivo com Python separando ele em chunks de 100000 e com isso faço filtros e cruzamentos necessários. Roda muito rápido. Veja se serve ou coloque seu código aqui para vermos

O código no momento está assim:

#Pega todas as cidades e o código dela e salva em uma lista de listas. O primeiro elemento de cada lista é o código e o segundo o nome
cidades = []
with open(‘cidades.csv’) as csv_file:
csv_reader = csv.reader(csv_file, delimiter=’,’)
for row in csv_reader:
cidades.append(row)

#Abre o dataset grande
#dados_1= pd.read_csv(“dados_1”)

#Guarda os dados em uma lista
#nomes_dados_1 = list(dados_1[“nome”])

#Cria os objetos para fazer o loop entre os diferentes documentos
meses = [“01”, “02”, “03”, “04”, “05”, “06”, “07”, “08”, “09”]
#Faz os loops para fazer os cruzamentos
for mes in meses:
df = pd.read_csv(“2019” + mes + “.csv”, encoding=“iso-8859-1”, sep=";")
for cidade in cidades:
#Mantém só o município a ser investigado
cid = df[df[“CÓDIGO MUNICÍPIO”] == int(cidade[0])]

    #Transforma nomes em uma lista
    lista_nomes = list(cid["NOME"])
    #Pega os nomes iguais nos dois bancos de dados
    nomes_iguais = list(set(nomes_dados_1 & set(lista_nomes))

O que você precisa comparar são nomes de cidades, certo?

Primeiro, toma cuidado com a acentuação para comparar - tem jeito de retirar - e também é bom transformar tudo em upper

Depois, não sei se comparar listas é o mais seguro num caso com vários arquivos. Talvez você possa transformar tudo em dataframe

Imaginando que você quer comparar dois dataframes:

# Cria um chunk de 100 mil para o arquivo muito grande, aqui o dados_1
TextFileReader = pd.read_csv('dados_1',\
                                 chunksize=100000,\
                                 sep=',',\
                                 names=['nome_cidade'],\
                                 dtype={'nome_cidade': str})

# imagine que df_compara é um dataframe com a coluna 'nome_cidade'
# e que o arquivo dados_1 também tem uma coluna com o mesmo nome (poderia ser outro, é só mudar)

conta = 0
for df_arquivo in TextFileReader:
	# merge compara e une dois dataframes a partir de valores iguais
    	nomes_iguais = pd.merge(df_compara, df_arquivo, left_on='nome_cidade', right_on='nome_cidade')

    	# Testa se o merge não é vazio
    	if nomes_iguais.empty is False:
    		# Testa se é a primeira vez
    	        if conta == 0:
    	            df_final = nomes_iguais
    		# Na segunda vez faz append no dataframe final
    	        else:
    	            df_final = df_final.append(nomes_iguais)
        	
        conta = conta + 1

E também para esclarecer dúvidas é sempre bom indicar como é cada arquivo que você possui: qual o nome do arquivo, quais as colunas têm, são de qual tipo… - se quiser detalha isso que tento mandar um código completo

Obrigado pelas respostas, Reinaldo. Vou testar e conto se funcionou!

1 Curtida

Reinaldo, usei o merge ao invés de comparar as duas listas e ficou MUITO mais rápido. Obrigado pela ajuda!

2 Curtidas

Se for para cruzar cidades, veja se não vale a pena transformá-las em category em vez de trabalhar com string. Isso pode reduzir o consumo de memória e tornar o processamento mais rápido. Escrevi sobre isso neste post (desculpa o merchan, mas achei válido compartilhar).

3 Curtidas