2016-07-28 23 views
0

Ich versuche, eine CSV-Datei zu komprimieren, ohne Verwendung von 3rd Party oder Framework bereitgestellten Komprimierungsbibliotheken.CSV-Dateikomprimierung ohne Verwendung vorhandener Bibliotheken in Python

Ich habe versucht, was ich denken möchte, alles. Ich schaute auf Huffman, aber da ich diese Lösung nicht verwenden darf, habe ich versucht, meine eigene zu machen.

Ein Beispiel:

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 

machte ich einen Algorithmus, der jedes Zeichen zählt und gibt mir an, wie oft sie schon verwendet worden, und, je nachdem, wie viel Zeit sie eine Reihe gewidmet.

',' --- 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)] 

Anstatt also beispielsweise die Speicherung ord ('H') = 72, gebe I H den Wert 12, und so weiter.

Aber wenn ich alle Zeichen auf meine Werte ändere, ist mein generiertes cvs (> 40MB) immer noch größer als das Original (19MB).

Ich versuchte sogar die Alternativen, um die Liste in 2 zu teilen. D. H. Für eine Zeile machen Sie zwei Zeilen.

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

Aber immer noch größer, sogar größer als meine "Huffman" Version.

FRAGE: jemand irgendwelche Vorschläge haben, wie man 1.Read eine CSV-Datei, das ist 2.use etwas ein lib. oder dritte Partei. 3.generiere und schreibe eine kleinere .csv Datei?

Für Schritt 2 Ich frage nicht nach einer vollständigen berechneten Lösung, nur Vorschläge, wie Sie die Datei minimieren, indem Sie jeden Wert als eine Liste schreiben?

usw.

Danke

+0

Warum Sie nicht möchten, vorhandene Bibliotheken benutzen? – MattDMo

+0

die Zuweisungen sagen nicht zu :) –

Antwort

0

Es ist unklar, ob Sie einen generischen Komprimierungsalgorithmus oder einen benutzerdefinierten Komprimierungsalgorithmus erstellen müssen, der für diese Art von Daten angemessen funktioniert.

Es ist auch unklar, ob die Ausgabe eine andere CSV, eine Zeichenfolge aus druckbaren ASCII-Zeichen oder einfache binäre Daten sein soll.

Ich gehe davon aus, dass wir über einen benutzerdefinierten Algorithmus und eine CSV-Ausgabe sprechen.(Die gleichen Prinzipien würden ohnehin auf ein anderes Ausgabeformat anzuwenden.)

Es scheint, dass Sie Ihre Eingabe gut formatiert ist und wiederholen immer die gleiche Art von Feldern:

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 

Gebäude Wörterbücher

See Wie viele unterschiedliche Codes werden in Spalte 0 verwendet und wie viele unterschiedliche Kombinationen von Spalte 1 und Spalte 2 haben Sie.

Wenn dieselben Werte häufig verwendet werden, lohnt es sich, Wörterbücher zu erstellen, die nur einmal gespeichert und dann in den komprimierten Zeilen referenziert werden.

Zum Beispiel:

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

So 6NH8 als 0 verwiesen würde, 6AH8 als 1 usw.

In der gleichen Weise, wie F,A0 und F,B als 1 verwiesen werden würde.

Encoding Zeitstempel in einem kürzeren Format

Unter der Annahme, dass Spalten # 4 und # 5 sind in der Tat der Zeitstempel, schnell zu gewinnen wären, den Mindestwert zu speichern und sie von dem Ist-Wert in jeder komprimierten Zeile subtrahieren.

minimum_timestamp = 60437395 

Daher 60541569 wird 60.541.569 - 60437395 = 104174.

Beispiel Ausgabe

Hier ist, was wir bekommen, wenn diese beiden einfachen Methoden zu Ihrem Beispiel Eingabe Anwendung:

# 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 

Sie könnten auch in Spalte 5 den Unterschied zwischen Spalte 5 und Spalte 4 speichern, wenn sich herausstellt, dass sie zusammenpassen dem "Anfang von etwas" und "Ende von etwas" entsprechen.

Die Größe der komprimierten Nutzlast beträgt etwa 70% der Größe der ursprünglichen Eingabe. (Denken Sie daran, dass die Größe des Headers vernachlässigbar werden sollte, wenn Sie viel mehr Zeilen haben.)

Ihr Beispiel ist zu kurz, um andere offensichtliche Muster für die restlichen Felder zu erkennen, aber hoffentlich werden Ihnen diese Beispiele einige Ideen geben .

UPDATE

Es stellt sich heraus, dass die Zeitstempel in der Anzahl der Millisekunden seit Mitternacht verstrichen exprimiert werden. Sie sind wahrscheinlich gleichmäßig in 0-86999999 verteilt und es ist nicht möglich, ein Minimum zu subtrahieren.

Diese Zahlen können jedoch kompakter codiert werden als die ASCII-Darstellung ihres Dezimalwerts.

Der einfachste Weg ist, sie zu hexadezimal konvertieren:

60541567 = 39BCA7F 

Eine etwas kompliziertere Art und Weise ist es, sie in Base64 zu codieren:

  1. Convert Zeitstempel in seine 4-Byte-Darstellung (alle Werte von 0 bis 86399999 passen in 4 Bytes):

  2. Erstellen Sie eine Zeichenfolge aus den 4 entsprechenden Zeichen und kodieren Sie sie in Base64.

Zum Beispiel:

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

danke :) Ich werde es versuchen und zurückkommen : D –

+0

danke, deine Lösung hat funktioniert, ABER ich habe immer noch Probleme mit den Zeitstempeln, du bist absolut richtig, wenn es darum geht, die Aufgabe zu verstehen. aber die Möglichkeit, den minimalen Zeitstempel zu machen, funktioniert nicht, weil der Zeitstempel manchmal "68" ist und es Millisekunden nach Mitternacht ist. Kennen Sie eine andere Lösung, um die Zeitstempel zu "minimieren"? in der ursprünglichen Datei gibt es 500 000 Zeilen (19,1 MB), wenn ich die Art wiederbeschreib, wie Sie ohne Zeitstempel beschreiben, ist die Datei viel viel kleiner –

+0

Bitte sehen Sie meine aktualisierte Antwort für einige alternative Möglichkeiten. – Arnauld

0

Versuchen Sie Ihren Algorithmus auf den Inhalt jeder Zelle statt einzelner Zeichen laufen und dann eine neue CSV-Datei mit den komprimierten Zellenwerte zu schaffen.

Wenn die von Ihnen bereitgestellten Daten ein Beispiel für die größere Datei sind, sollten Sie den Komprimierungsalgorithmus für jede Spalte separat ausführen. Zum Beispiel helfen, es kann nur Spalten 0,4 und 5

für das Lesen und Schreiben von CSV-Dateien, die csv Modul überprüfen zu komprimieren, wo man Dinge wie tun können:

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

Danke, daran habe ich nicht gedacht. Zum Beispiel Speichern von Wiedereröffnungsspalten wie "6NH8". Also schlagen Sie immer noch vor, auf csv als Diktat zu schreiben, aber mit "Zahlen", die Spalten entsprechen? –

+0

ging durch 500 000 Zeilen .. die Zeiten treten manchmal dreimal auf aber am ehesten einmal. Gleiche Sache mit den 4 ersten Buchstaben und Zahlenkombinationen. also das hat nicht so viel geholfen :( –

0

Für jede Zeile suchen übereinstimmende Teilstrings in der vorherigen Zeile oder den vorherigen Zeilen. Senden Sie für jede übereinstimmende Teilzeichenfolge (z. B. 6NH8,F,A,0,6054156 oder ,78.78,2) die Länge der Übereinstimmung und die Entfernung zurück, um stattdessen zu kopieren. Dies wird LZ77-Komprimierung genannt.

+0

Danke, aber mir ist aufgefallen, dass die Größe meines Wörterbuchs in der Ausgabe csv zählt. Dh, 0: ["123", 345 "," 678 "] .. also irgendwie ich muss ich die Anzahl der Werte in meinem Diktat minimieren? Oder denke ich falsch? –

+0

Verwenden Sie Binärzahlen. Nicht ASCII-Darstellungen von Zahlen. –

+0

Ja, ich habe versucht, aber durch meine eigene Version von Huffman, habe ich alle diese in binäre [(' , (0), (5), (6), (0), (7), (8), (8), , 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)]. Also alle Zahlen habe ich in Binärdateien umgewandelt und "," auf 0 dann auf Binär umgeschaltet, aber die Datei ist immer noch größer als das Original –