2016-07-28 4 views
0

Я пытаюсь сжать CSV-файл без использования каких-либо сторонних или инфраструктурных библиотек сжатия.сжатие файла csv без использования существующих библиотек в Python

Я пробовал, что я хочу думать, все. Я посмотрел на Хаффмана, но, поскольку мне не разрешено использовать это решение, я пытался сделать свое.

Пример:

6NH8,F,A,0,60541567,60541567,78.78,20 
6NH8,F,A,0,60541569,60541569,78.78,25 
6AH8,F,B,0,60541765,60541765,90.52,1 
QMH8,F,B,0,60437395,60437395,950.5,1 

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

',' --- 28 
'5' --- 18 
'6' --- 17 
'0' --- 15 
'7' --- 10 
'8' --- 8 
'4' --- 8 
'1' --- 8 
'9' --- 6 
'.' --- 4 
'3' --- 4 
'\n'--- 4 
'H' --- 4  
'F' --- 4 
'2' --- 3 
'A' --- 3 
'N' --- 2 
'B' --- 2 
'M' --- 1 
'Q' --- 1 

[(',', 0), ('5', 1), ('6', 2), ('0', 3), ('7', 4), ('8', 5), 
('4', 6), ('1', 7), ('9', 8), ('.', 9), ('3', 10), ('\n', 11), 
('H', 12), ('F', 13), ('2', 14), ('A', 15), ('N', 16), ('B', 17), 
('M', 18), ('Q', 19)] 

Таким образом, вместо того, чтобы хранить, например, Ord ('Н') = 72, я дам H значение 12, и так далее.

Но, когда я меняю все символы на мои значения, мои сгенерированные cvs (> 40 МБ) по-прежнему больше оригинала (19 МБ).

Я даже попробовал альтернативы, чтобы разделить список на 2. i.e для одной строки сделать это двумя строками.

[6NH8,F,A,0,] 
[60541567,60541567,78.78,20] 

Но все же больше, даже больше, чем моя версия «huffman».

ВОПРОС: Кто-нибудь есть какие-либо предложения о том, как 1.read файл .csv, 2.Use что-то вот в LIB. или третьей стороной. 3.генерировать и писать меньше .csv-файл?

Для шага 2 Я не прошу полного вычислительного решения, просто советы о том, как свести к минимуму файл, например, написать каждое значение как один список? и т.д.

Спасибо

+0

Почему вы не хотите использовать существующие библиотеки? – MattDMo

+0

заданий говорит не :) –

ответ

0

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

Также неясно, должен ли вывод быть другой CSV, строка из печатных символов ASCII или простых двоичных данных.

Я собираюсь предположить, что мы говорим о пользовательском алгоритме и выходе CSV.(Те же самые принципы будут применяться к другому выходному формату в любом случае.)

Оказывается, что ваш вход хорошо отформатирован и всегда повторять один и тот же вид полей:

0 '6NH8'  : 4-character code 
1 'F'  : character 
2 'A'  : character 
3 '0'  : integer 
4 '60541567' : integer \_ some kind of 
5 '60541567' : integer/timestamps? 
6 '78.78' : float 
7 '20'  : integer 

Строительных словари

См сколько различных кодов используется в столбце № 0 и сколько различных комбинаций столбца №1 + столбца №2 у вас есть.

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

Например:

column0_dictionary = [ '6NH8', '6AH8', 'QMH8' ] 
column12_dictionary = [ 'FA', 'FB' ]; 

Так, 6NH8 будет ссылаться как 0, 6AH8 как 1 и т.д.

Таким же образом, F,A будут ссылаться как 0 и F,B как 1.

Кодирование метки времени в более коротком формате

Если предположить, что столбцы # 4 и # 5, действительно временные метки, быстрый выигрыш будет хранить минимальное значение и вычесть его из фактического значения в каждой сжатой строке.

minimum_timestamp = 60437395 

Поэтому 60541569 становится 60541569 - 60437395 = 104174.

Пример вывода

Вот что получается при применении этих двух простых методов к вашему примеру ввода:

# header 
6NH8,6AH8,QMH8 
FA,FB 
60437395 
# payload data 
0,0,0,104172,104172,78.78,20 
0,0,0,104174,104174,78.78,25 
1,1,0,104370,104370,90.52,1 
2,1,0,0,0,950.5,1 

Вы также можете сохранить в столбце №5 разницу между столбцом № 5 и столбцом № 4, если окажется, что они соответствуют «началу чего-то» и «концу чего-то».

Размер сжатой полезной нагрузки составляет около 70% от размера исходного ввода. (Имейте в виду, что размер заголовка должен стать незначительным, если у вас много больше строк.)

Ваш пример слишком короткий, чтобы обнаружить любые другие очевидные шаблоны для остальных полей, но, надеюсь, эти примеры дадут вам некоторые идеи ,

UPDATE

Оказывается, что временные метки выражается в количестве миллисекунд, прошедших с полуночи. Поэтому они, вероятно, равномерно распределены в 0-86399999, и невозможно вычесть минимум.

Эти цифры, однако, могут быть закодированы более компактно, чем ASCII-представление их десятичного значения.

Самый простой способ, чтобы преобразовать их в шестнадцатеричное:

60541567 = 39BCA7F 

Несколько более сложный способ является кодировать их в Base64:

  1. Преобразовать метку времени к его 4-байтового представления (все значения от 0 до 86399999 будут входить в 4 байта):

  2. Создайте строку из 4 соответствующих символов и закодируйте ее в Base64.

Например:

60541567 = 03 9B CA 7F # in hexadecimal and big-endian order 

BASE64(CHR(0x03) + CHR(0x9B) + CHR(0xCA) + CHR(0x7F)) = A5vKfw 
# here without the padding characters 
+0

спасибо :) Я попробую и вернусь : D –

+0

спасибо, ваше решение сработало, НО у меня все еще проблема с отметками времени, вы абсолютно правильно, когда приходит понимание задания. но способ выполнить минимальную метку времени не работает, потому что иногда временная метка «68», и она составляет миллисекунды после полуночи. знаете ли вы другое решение «свести к минимуму» временные метки? в исходном файле есть 500 000 строк (19.1MB), когда я повторно храню способ, который вы описываете без отметки времени, файл намного меньше –

+0

Пожалуйста, см. мой обновленный ответ для некоторых альтернативных способов. – Arnauld

0

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

Если данные, которые вы предоставили, являются примером более крупного файла, вам может потребоваться выполнить алгоритм сжатия для каждого столбца отдельно. Например, он может помочь только сжать столбцы 0,4 и 5.

Для чтения и записи файлов CSV ЗАКАНЧИВАТЬ csv модуль, где вы можете делать такие вещи, как:

import csv 
with open('eggs.csv', 'rb') as csvfile: 
    spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|') 
    for row in spamreader: 
     print ', '.join(row) 
+0

Спасибо, я об этом не думал. Чтобы хранить данные, см. Столбцы повторного заполнения, например «6NH8». Итак, вы все же предлагаете писать на csv как dict, но с «числами», равными столбцам? –

+0

прошел через 500 000 строк .. времена встречаются иногда три раза, но, скорее всего, один раз. то же самое с четырьмя комбинациями первой буквы и номера. так что это не помогло :( –

0

Для каждой линии, поиск соответствующие подстроки в предыдущей строке или строках. Для каждой подходящей подстроки (например, 6NH8,F,A,0,6054156 или ,78.78,2) отправьте длину совпадения и расстояние обратно, чтобы скопировать. Это называется сжатием LZ77.

+0

Спасибо, но я заметил, что размер моего словаря в выводе csv имеет значение. Т.е., 0: ["123", 345 "," 678 "] .. Так что-то я нужно свести к минимуму количество значений в моем dict? Или я думаю неправильно –

+0

Использовать двоичные числа. Не ASCII-представления чисел. –

+0

Да, я пробовал это, но через мою собственную версию Хаффмана я превратил все эти в двоичные [ , ', 0), (' 5 ', 1), (' 6 ', 2), (' 0 ', 3), (' 7 ', 4), (' 8 ', 5), (' 4 ' , 6), ('1', 7), ('9', 8), ('.', 9), ('3', 10), ('\ n', 11), ('H', 12), ('F', 13), ('2', 14), ('A', 15), ('N', 16), ('B', 17), ('M', 18) , ('Q', 19)]. Итак, все числа, которые я превратил в двоичные, и переключили «,» на 0, затем на двоичный, но файл по-прежнему больше оригинала –

 Смежные вопросы

  • Нет связанных вопросов^_^