Переиндексация большого файла CSV

11

Я просмотрел ответы в этой полезной ветке , но моя проблема, похоже, иная, поэтому я не могу придумать хорошего ответа (по крайней мере, с sed).

У меня есть большой файл CSV (200+ ГБ) со строками, которые выглядят следующим образом:

<alphanumerical_identifier>,<number>

где <alphanumerical_identifier>уникально для всего файла. Я хотел бы создать отдельный файл, который заменяет первый столбец индексом , т.е.

<index>,<number>

так что мы получаем:

1, <number>
2, <number>
3, <number>

Может awkгенерировать увеличивающийся индекс без загрузки полного файла в память?

Поскольку индекс увеличивается монотонно, может быть, даже лучше просто удалить индекс. Будет ли решение для этого быть другим?

<number>
<number>
<number>
Амелио Васкес-Рейна
источник
Я не уверен в целесообразности этого решения. Но как насчет того, чтобы просто сгенерировать столько же чисел, сколько в файле CSV в отдельном файле, а затем просто добавить второй столбец файла CSV в этот файл?
Рамеш
@Ramesh Это прекрасно, если вывод правильный.
Амелио Васкес-Рейна
2
Я подозреваю, что я что-то неправильно понимаю; иначе awk -F, '{print ++n, $2}'бы сработало. Или awk -F, '{print $2}'для второго варианта.
G-Man говорит: «Восстановите Монику»
2
@ G-Man, это, вероятно, хотя FNRбы так же хорошо, как и++n
iruvar
1
Я бы трижды проверил, что вы действительно можете избавиться от этого Uniq Identifier ... почему бы не добавить первый (третий) столбец с индексом, но при этом сохранить идентификатор? этот идентификатор не используется где - либо еще?
Оливье Дюлак

Ответы:

13

Не возле терминала для тестирования, а как насчет часто пропускаемой nlкоманды? Что-то вроде:

cut -f 2 -d , original.csv | nl -w 1 -p -s , > numbered.csv

епископ
источник
1
PS: файл CSV 200 ГБ? Ух ты, и я подумал, что работа с Североамериканской базой данных перенесенных номеров в качестве CSV (пара DVD) была огромной!
епископ
1
Это работает, хотя после номера есть большой пробел. Я бы заменил его на:cut -d, -f 2- /tmp/aa | nl -w 1 -p -s ,
Анхель
@Angel: Спасибо, обновил мой ответ, чтобы использовать параметр ширины -w 1вместо нумерации слева.
епископ
Спасибо @bishop - Куда идут входные и выходные имена файлов?
Амелио Васкес-Рейна
1
@ user815423426 Да, cutкоманда перед символом канала ( |) даст вам только второй столбец, эффективно имеющий неявные номера строк.
епископ
7

Вот несколько подходов, но ни один из них не приблизится к скорости cutи nlрешению выше:

  1. AWK

    awk -F, '{$1=NR;print $1","$2;}' file.csv > newfile.csv
  2. Perl

    perl -pe 's/[^,]+/$./' file.csv > newfile.csv

    или

    perl -F, -ane '$F[0]=$.; print join ",", @F' file.csv
  3. Shell (но я не рекомендую его для файла 200G, это займет много лет)

    i=1; while IFS=, read foo num; do 
            printf "%d,%s\n" $((i++)) $num; 
    done < file.csv > newfile.csv
    

Вышеуказанные решения отсортированы в порядке скорости. Я проверил на своем ноутбуке и файл 40M, и они взяли (в среднем 10 прогонов) 2.2282 (awk), 2.4555 (1-й perl), 3.1825s (2-й perl) и колоссальные 48.6035s для оболочки. Очень умный cutи nlрешение , которое вы уже было около 4 раза быстрее 0.6078s.

Тердон
источник
Хорошо, спасибо за статистику! Результат снаряда меня несколько удивляет. Если вы замените printfна echo, значительно ли улучшится время?
епископ
2
Файл 40G обрабатывается за 2,2282 секунды? Где мне взять этот ноутбук?
Джон Б.
2
@JohnB хм, да, извините, это было 40M, а не G :)
terdon
Мне нравится сброс $1подхода с awk. cutРешение, безусловно , гораздо быстрее, но это и следовало ожидать , поскольку она не заменит <alphanumerical_identifier>ни с чем. Я думаю , что самый быстрый awkвариант может быть что - то вроде: mawk 'BEGIN{FS=OFS=","}{$1=NR}1' file.csv > newfile.csv.
Джон Б.
@JohnB ах, да, я предполагаю, что использование OFSвместо явной печати ,будет немного быстрее, и это может привести к значительной разнице в больших файлах.
Terdon