Divisão de um CSV de 7 milhões de linhas por uma coluna específica


2

Como eu iria dividir um arquivo CSV muito grande (7 milhões de linhas) em várias folhas / arquivos diferentes por uma coluna numérica específica? Deve dividir em cerca de 10 arquivos diferentes.


Como exatamente o arquivo é dividido? Cada coluna vai para um arquivo diferente?
— Cristian Ciupitu

Em que sistema operacional, programa, etc? (por exemplo, Windows + Excel, Linux + Libreoffice ...)
— Wilf

@CristianCiupitu Eu gostaria de dividir os dados com base em uma coluna. Essa coluna 1 tem cerca de 10 valores diferentes. Então, quero colocar cada linha com seu valor de coluna respeitado em um arquivo separado. Por isso, deve sair para 10 arquivos diferentes.
— BrandonMXB

Respostas:


3

Usa isto Python 3 programa:

#!/usr/bin/env python3
import binascii
import csv
import os.path
import sys
from tkinter.filedialog import askopenfilename, askdirectory
from tkinter.simpledialog import askinteger

def split_csv_file(f, dst_dir, keyfunc):
    csv_reader = csv.reader(f)
    csv_writers = {}
    for row in csv_reader:
        k = keyfunc(row)
        if k not in csv_writers:
            csv_writers[k] = csv.writer(open(os.path.join(dst_dir, k),
                                             mode='w', newline=''))
        csv_writers[k].writerow(row)

def get_args_from_cli():
    input_filename = sys.argv[1]
    column = int(sys.argv[2])
    dst_dir = sys.argv[3]
    return (input_filename, column, dst_dir)

def get_args_from_gui():
    input_filename = askopenfilename(
        filetypes=(('CSV', '.csv'),),
        title='Select CSV Input File')
    column = askinteger('Choose Table Column', 'Table column')
    dst_dir = askdirectory(title='Select Destination Directory')
    return (input_filename, column, dst_dir)

if __name__ == '__main__':
    if len(sys.argv) == 1:
        input_filename, column, dst_dir = get_args_from_gui()
    elif len(sys.argv) == 4:
        input_filename, column, dst_dir = get_args_from_cli()
    else:
        raise Exception("Invalid number of arguments")
    with open(input_filename, mode='r', newline='') as f:
        split_csv_file(f, dst_dir, lambda r: r[column-1]+'.csv')
        # if the column has funky values resulting in invalid filenames
        # replace the line from above with:
        # split_csv_file(f, dst_dir, lambda r: binascii.b2a_hex(r[column-1].encode('utf-8')).decode('utf-8')+'.csv')

Salve como split-csv.py e executá-lo a partir do Explorer ou da linha de comando.

Por exemplo, para dividir superuser.csv baseado na coluna 1 e gravar os arquivos de saída dstdir usar:

python split-csv.py superuser.csv 1 dstdir

Se você executá-lo sem argumentos, uma GUI baseada em Tkinter solicitará que você escolha o arquivo de entrada, a coluna (índice baseado em 1) e o diretório de destino.


Sim! Muito obrigado! Na verdade funcionou. Eu estava prestes a recorrer à codificação de um script para fazer o trabalho, em Java. Mas woo!
— BrandonMXB

Estou feliz que funcionou. Se eu soubesse que você é um usuário avançado, eu não perderia tempo com a GUI :-) Um voto junto com o existente ✔ seria bom também :-)
— Cristian Ciupitu

Nãoooo haha. Eu gostei muito do GUI haha. Eu selecionei o seu como a resposta, mas infelizmente desde que eu entrei nesta comunidade, eu preciso de um pouco mais de reputação. Eu geralmente estou na comunidade StackOverflow haha. E hmm ... Por algum motivo depois de escrever a linha, ela escreve outra linha. Alguma sugestão? É meio chato que todas as outras linhas estejam em branco.
— BrandonMXB

Entendo. Pela maneira com toda a justiça eu votei o resposta do awk . Eu não entendo a coisa em branco. Talvez tenha algo a ver com os finais da linha. Verifique os arquivos com um editor (talvez vim ).
— Cristian Ciupitu

@BrandonMXB, tente novamente, acho que consertei o problema.
— Cristian Ciupitu

4

Isto pode ser tão simples como este one-liner com awk:

awk -F ',' '{ print > ("split-" $1 ".csv") }' 7mil.csv
  • O arquivo de entrada aqui é 7mil.csv
  • O número da coluna decisiva é indicado com o cifrão. Se fosse a terceira coluna, seria $3 ao invés de $1
  • O valor da coluna é usado para gerar o nome do arquivo resultante. Então, por exemplo, cada linha com o valor 42 estará em um arquivo chamado split-42.csv
  • O separador de campo é a vírgula
    • que funciona porque / se o valor é numérico e não tem aspas que precisam ser removidas
    • mas também requer que não haja vírgulas em nenhuma string no arquivo (pelo menos não antes da coluna numérica)

Então, isso apenas lê todas as linhas e as imprime no arquivo que corresponde ao valor. Observe que ele é adicionado ao arquivo, portanto, se você executá-lo duas vezes, todos os dados serão duplicados; Portanto, verifique se não há arquivos com esse padrão de nomenclatura para iniciar: del split-*.cvs

A parte difícil para tentar isso é instalar awk no Windows. Há gawk para Windows e um algumas dicas para executá-lo aqui .


Tenho certeza que isso teria funcionado também, mas eu vi a solução acima primeiro. Muito obrigado! :)
— BrandonMXB

1
@ Ken: Sua resposta é muito apreciada! Este one-liner era exatamente o que eu precisava para um pipeline de dados em um sistema Linux :)
— Jubbles

1

Delimitar pode fazer isso. Ele abre arquivos csv grandes muito rápidos ("até 2 bilhões de linhas e 2 milhões de colunas grandes!"). Use a divisão verticalmente e / ou escolha suas colunas.

Outro software que pode ser capaz de fazer isso é Emeditor .

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.