Как разделить огромный CSV-файл на основе содержимого первого столбца? - PullRequest
10 голосов
/ 29 февраля 2012
  • У меня есть 250 МБ + огромный CSV-файл для загрузки
  • формат файла group_id, application_id, reading, и данные могут выглядеть как
1, a1, 0.1
1, a1, 0.2
1, a1, 0.4
1, a1, 0.3
1, a1, 0.0
1, a1, 0.9
2, b1, 0.1
2, b1, 0.2
2, b1, 0.4
2, b1, 0.3
2, b1, 0.0
2, b1, 0.9
.....
n, x, 0.3(lets say)  
  • Я хочу разделить файл на основе group_id, поэтому на выходе должно быть n файлов, где n=group_id

Вывод

File 1

1, a1, 0.1
1, a1, 0.2
1, a1, 0.4
1, a1, 0.3
1, a1, 0.0
1, a1, 0.9

и

File2
2, b1, 0.1
2, b1, 0.2
2, b1, 0.4
2, b1, 0.3
2, b1, 0.0
2, b1, 0.9
.....

и

File n
n, x, 0.3(lets say)  

Как я могу сделать это эффективно?

Ответы [ 7 ]

17 голосов
/ 29 февраля 2012

awk способен:

 awk -F "," '{print $0 >> ("FILE" $1)}' HUGE.csv
9 голосов
/ 29 февраля 2012

Если файл уже отсортирован по group_id, вы можете сделать что-то вроде:

import csv
from itertools import groupby

for key, rows in groupby(csv.reader(open("foo.csv")),
                         lambda row: row[0]):
    with open("%s.txt" % key, "w") as output:
        for row in rows:
            output.write(",".join(row) + "\n")
4 голосов
/ 29 февраля 2012

Sed one-liner:

sed -e '/^1,/wFile1' -e '/^2,/wFile2' -e '/^3,/wFile3' ... OriginalFile 

Единственным недостатком является то, что вам нужно поместить в n -e операторы (представленные многоточием, которые не должныпоявиться в финальной версии).Таким образом, эта однострочная строка может быть довольно длинной.

Плюсы в том, что она делает только один проход через файл, сортировка не предполагается, и Python не нужен.Плюс, это чертовски лайнер!

2 голосов
/ 29 февраля 2012

Если строки отсортированы по group_id, тогда itertools.groupby будет здесь полезно. Поскольку это итератор, вам не нужно загружать весь файл в память; Вы все еще можете написать каждый файл построчно. Используйте csv для загрузки файла (если вы еще не знали об этом).

1 голос
/ 29 февраля 2012

Вот немного еды для вас:

import csv
from collections import namedtuple

csvfile = namedtuple('scvfile',('file','writer'))

class CSVFileCollections(object):

    def __init__(self,prefix,postfix):
        self.prefix = prefix
        self.files = {}

    def __getitem__(self,item):
        if item not in self.files:
            file = open(self.prefix+str(item)+self.postfix,'wb')
            writer = csv.writer(file,delimiter = ',', quotechar = "'",quoting=csv.QUOTE_MINIMAL)
            self.files[item] = csvfile(file,writer) 
        return self.files[item].writer

    def __enter__(self): pass

    def __exit__(self, exc_type, exc_value, traceback):
        for csvfile in self.files.values() : csvfile.file.close()


with open('huge.csv') as readFile, CSVFileCollections('output','.csv') as output:
    reader = csv.reader(readFile, delimiter=",", quotechar="'")
    for row in reader:
        writer = output[row[0]]
        writer.writerow(row)
1 голос
/ 29 февраля 2012

Как насчет:

  • Считать входной файл по одной строке за раз
  • split() каждая строка на ,, чтобы получить group_id
  • Для каждого нового найденного group_id откройте выходной файл
    • добавьте каждый groupid к набору / dict по мере их нахождения, чтобы вы могли отслеживать
  • написать строкув соответствующий файл
  • Готово!
1 голос
/ 29 февраля 2012

Если они отсортированы по идентификатору группы, вы можете использовать модуль csv, чтобы перебирать строки в файлах и выводить их. Вы можете найти информацию о модуле здесь .

...