Разделить CSV-файл тысячи раз на основе группового - PullRequest
1 голос
/ 12 апреля 2020

(адаптация вопроса Дэвида Эриксона здесь )

С учетом файла CSV со столбцами A, B и C и некоторыми значениями:

echo 'a,b,c' > file.csv
head -c 10000000 /dev/urandom | od -d | awk 'BEGIN{OFS = ","}{print $2, $3, $4}' | head -n 10000 >> file.csv

Мы бы хотели отсортировать по столбцам a и b:

sort -t ',' -k1,1n -k2,2n file.csv > file_.csv
head -n 3 file_.csv
>a,b,c
3,50240,18792
7,54871,39438

А затем для каждой уникальной пары (a, b) создать новый CSV под названием '{a}_Invoice_{b}.csv'.

Основная задача, похоже, заключается в из-за накладных расходов ввода-вывода при написании тысяч файлов - я начал пробовать с awk, но столкнулся с awk: 17 makes too many open files.

Есть ли более быстрый способ сделать это, в awk, Python или какой-то другой другой язык сценариев?

Дополнительная информация:

  • Я знаю, что могу сделать это в Pandas - я ищу более быстрый способ использования обработки текста
  • Хотя я использовал urandom для генерации образцов данных, реальные данные имеют повторяющиеся значения: например, несколько строк, где a=3, b=7. Если это так, они должны быть сохранены как один файл. (Идея состоит в том, чтобы скопировать Pandas 'groupby -> to_csv)

Ответы [ 2 ]

3 голосов
/ 12 апреля 2020

В python:

import pandas as pd

df = pd.read_csv("file.csv")
for (a, b), gb in df.groupby(['a', 'b']):
    gb.to_csv(f"{a}_Invoice_{b}.csv", header=True, index=False)

В awk вы можете разделить так, как вам нужно, вам нужно будет поместить заголовок обратно в каждый результирующий файл:

awk -F',' '{ out=$1"_Invoice_"$2".csv"; print >> out; close(out) }' file.csv

С добавлением строки заголовка обратно:

awk -F',' 'NR==1 { hdr=$0; next } { out=$1"_Invoice_"$2".csv"; if (!seen[out]++) {print hdr > out} print >> out; close(out); }' file.csv

Преимущество этого последнего примера состоит в том, что входные данные file.csv не нужно сортировать и они обрабатываются за один проход.

1 голос
/ 12 апреля 2020

Поскольку ваш ввод должен быть отсортирован по ключевым полям, все что вам нужно:

sort -t ',' -k1,1n -k2,2n file.csv |
awk -F ',' '
NR==1 { hdr=$0; next }
{ out = $1 "_Invoice_" $2 ".csv" }
out != prev {
    close(prev)
    print hdr > out
    prev = out
}
{ print > out }
'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...