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.

BrandonMXB
fonte
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.

Cristian Ciupitu
fonte
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 .

Ken
fonte
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 .

Erb
fonte