Как отсортировать CSV-файл python

Обновлено: 03.07.2024

За свою карьеру я дважды получал задание сравнить два больших файла CSV (значения, разделенные запятыми: текстовые файлы, соответствующие либо экспорту файла Excel, либо экспорту таблиц базы данных):

  • В первом случае это было сравнение сделок, заключенных с помощью настроенного программного пакета в независимой стране P1, и сделок, заключенных с помощью того же программного пакета, настроенного по-разному в стране P2. Необходимо было в первую очередь перекодировать информацию, чтобы затем распознать тех, кто отсутствовал в парижской системе, и тех, кто был изменен, чтобы обновить данные парижской базы данных. Каждый файл весил около 300 Мб, а на компьютерах было около 1 Гб оперативной памяти. Ожидается, что разработка ОС будет завершена в ближайшие 3 дня максимум. (Принцип: нам нужен результат за вчерашний день со временем выполнения менее 8 часов).
  • Во втором случае необходимо было согласовать потоковые файлы между двумя разными программными пакетами (старым, который нужно было вывести из эксплуатации, и новым), которые работали в условиях конкуренции, чтобы избежать регрессий. Каждый файл весил 2,5 Гб, и цель состояла в том, чтобы сравнивать их ежедневно менее чем за 2 часа. Разработка должна была начаться менее чем за две недели.

Чтобы иметь возможность сравнивать их, первый шаг (и самый сложный) состоит из сортировки двух файлов: сортируя их, мы можем уменьшить количество прочитанных строк, а также количество сравнений. К сожалению, сортировка файла требует его загрузки, а когда он большой, это усложняется.

2. Технические решения

2.1 Язык

Выбор языка сильно зависит от контекста:

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

2.2 Алгоритм

Выбор алгоритма будет определять производительность, а также осуществимость. Действительно, «загрузка CSV-файла» объемом 2,5 Гб в ОЗУ невозможна, если у вас нет исключительного объема памяти, запрещающего хранение файла в памяти. Сделайте несколько попыток и поэкспериментируйте, и вы обнаружите, что потребление памяти почти в 10 раз больше, когда мы вырезаем линии в векторе значений.

Вот небольшой пример:

Объединение ради победы

Вторая часть алгоритма состоит в объединении файлов 2 на 2, чтобы обеспечить сохранение сортировки. Мы будем читать по одной строке в каждом файле, сравнивать их и записывать наименьшую из них в файл результатов и заменять записанную строку следующей из того же исходного файла. Риск голода (мы израсходовали все строки в одном из двух файлов, но не в другом), тогда потребуется развить функцию сравнения, чтобы иметь возможность обрабатывать пустые строки: мы сдвигаем строку (четко определенную) в выходной файл.

5. Сортировка или ничего

Цель этой функции — организовать вырезание, а затем слияние до тех пор, пока вы не получите отсортированный файл. После вырезания мы объединим файлы 2 на 2: на каждом шаге мы делим количество файлов на 2. Мы должны продолжать, пока не будет больше одного файла. А в случае, когда на одном шаге нечетное количество файлов, будет файл для копирования с шага i на шаг i + 1.

Вот пример:

Заключение

Метод позволяет заменить проблемы с выделением памяти/управлением доступом к файлам. Таким образом, производительность будет зависеть от двух параметров:

  • Время доступа к диску: избегайте использования сетевого диска для управления временными файлами, предпочитайте локальный жесткий диск.
  • Количество строк при вырезании: чем меньше число, тем важнее файлы и, следовательно, тем дороже будет доступ к диску.

Необходимо откалибровать алгоритм в соответствии с используемой машиной (объемом памяти и жесткого диска) для выполнения операции и форматом CSV-файла. Это позволит сделать эффективный выбор количества строк для резки.

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

В этом упражнении мы будем использовать файл ratings.csv, который поставляется с базой данных фильмов.

< td>1425941529
userId movieId рейтинг отметка времени< /th>
0 1 110 1.0
1 1 147 4.5 1425942435

Давайте проверим размер нашего фрейма данных

Фрейм данных содержит примерно 26 миллионов записей. У каждого пользователя есть несколько записей. Давайте проверим, сколько уникальных пользователей.

Итак, в нашей базе данных 270 тысяч уникальных пользователей. Давайте посмотрим, сколько здесь уникальных фильмов.

Хорошо, представлено около 45 000 фильмов, для которых у нас есть оценки.

Давайте также проверим диапазон нашего рейтингового столбца. Для этого мы можем использовать метод description() для всего фрейма данных. Метод Describe() дает нам хорошую статистику.

userId movieId рейтинг отметка времени< /th>
число 2.602429e+07 2.602429e+07 2,602429e+07 2,602429e+07
среднее 1,350371e+05 1,584911e +04 3,528090e+00 1,171258e+09
станд. 7,817620e+04 3,108526e+04 1,065443e+00 2,052889e+08
мин th> 1.000000e+00 1.000000e+00 5.000000e-01 7.896520e+08
25% 6,716400e+04 1,073000e+03 3,000000e+00 9,907545e +08
50% 1,351630e+05 2,583000e+03 3,500000e+ 00 1,151716e+09
75% 2,026930e+05 6,503000e+03 4.000000e+00 1.357578e+09
макс. 2.708960e+05 1.762750e+05 5.000000e+00 1.501830e+09

Как мы видим выше, рейтинг имеет минимальное значение 0,5 и максимальное значение 5,0.

Теперь мы знаем наш фрейм данных намного лучше, давайте теперь выполним операции сортировки.

Как выполнить сортировку по значениям

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

< td>879251202
userId movieId рейтинг отметка времени< /th>
18471899 191698 1617 5.0
8646727 89135 491 5.0 860830376

Как мы видим выше, первые две строки теперь имеют рейтинг 5. Помните, что приведенная выше команда не сохранила данные в порядке убывания. Если мы хотим сохранить данные, используем опцию inplace=True

< td>879251202
userId movieId рейтинг отметка времени< /th>
18471899 191698 1617 5.0
8646727 89135 491 5.0 860830376

Для возрастания просто используйте параметр, восходящий=True, как показано ниже.

< td>1112330388
userId movieId рейтинг отметка времени< /th>
16757505 174227 3968 0,5
12103042 125498 86911 0,5 1307014797

Как отсортировать несколько столбцов в Pandas

Мы также можем сортировать по нескольким столбцам в Pandas, допустим, мы хотим отсортировать рейтинг от самого высокого до самого низкого, а затем от наивысшего к самому низкому идентификатору фильма.

< td>1501765780
userId movieId рейтинг отметка времени< /th>
83813 837 176271 5.0
24906715 258955 176219 5.0 1501539818

Как мы видим выше, рейтинг и movieId отображаются в порядке от наибольшего к наименьшему. Давайте добавим еще один столбец userId, в этом примере нет смысла сортировать movieId и userId, но для тренировки мы все равно это сделаем.

< td>1501765780
userId movieId рейтинг отметка времени< /th>
83813 837 176271 5.0
24906715 258955 176219 5.0 1501539818

Мы увидели, что ничего особенного не изменилось по сравнению с нашей предыдущей командой. Теперь давайте внесем небольшое изменение, отсортируем userId перед movieId и посмотрим, что получится

< td>1257032032
userId movieId рейтинг отметка времени< /th>
26024285 270896 60069 5.0
26024284 270896 58559 5.0 1257031564

Мы видим другой результат, чем только что произошло. Сначала мы отсортировали рейтинг, затем идентификатор пользователя. Поскольку 270896 дал более одного рейтинга фильмам, приведенный выше код сортирует movieId пользователя 270896 дальше от самого высокого к самому низкому.

Давайте рассмотрим содержательный пример. Давайте найдем среднюю оценку пользователя и отсортируем ее от самой высокой до самой низкой. Для этого запроса нам нужно будет сгруппировать по первому пользователю и применить усредненную операцию к рейтингу столбца, а затем отсортировать его по рейтингу. Давайте попробуем это.

Читайте также: