Dies ist meine erste Frage, also bitte verzeihen Sie alle Fehler.Python: Viele-zu-viele-Vergleich, um erforderliche Daten zu finden
Ich habe eine große Datei (CSV) mit mehreren (~ 10000000 +) Linien Informationen wie das folgende Beispiel:
date;box_id;box_length;box_width;box_height;weight;type
--snip--
1999-01-01 00:00:20;nx1124;10;4;5.5;2.1;oversea
1999-01-01 00:00:20;np11r4;8;3.25;2;4.666;local
--snip--
Mein Ziel ist es, durch jede Zeile zu lesen und die Büchse der Lautstärke und innerhalb von 1 berechnen Stundenfenster (zB 00:00:00 - 00:00:59) Ich muss aufzeichnen, wenn 2 oder mehr Boxen ein ähnliches Volumen haben (+ -10% Unterschied) und dann ihren Zeitstempel sowie ihren Typ aufzeichnen.
Im Moment ich bin mit einem Brute-Force-Ansatz:
- laufen durch jede Zeile
- berechnen Volumen
- zur nächsten Zeile und Rechenvolumen gehen
- vergleichen
- wiederholen bis 1 Std. Zeitdifferenz festgestellt
- Entfernen Sie die erste Box aus der Liste
- ein anderes Feld in die Liste
- wiederholen Sie den Vorgang mit dem zweiten Feld
Zum Beispiel hinzufügen, wenn mein 1 Stunde Fenster 1,2,3,4 hat, ich bin diesen
1
2 == 1
3 == 1 then == 2
4 == 1 then == 2 then == 3
5 == 2 then == 3 then == 4 # removed 1 from list(1hr window moved down)
6 == 2 then == 3 then == 4 then == 5
7 == 2 then == 3 then == 4 then == 5 then == 6
.... so on ....
tun
Das ist das Beste, was ich mir vorstellen kann, da ich jede Box innerhalb eines bestimmten Zeitfensters mit anderen vergleichen muss. Aber das ist im Moment sehr sehr langsam.
Ich bin auf der Suche nach einem besseren Algorithmus, aber ich bin mir unsicher, in welche Richtung ich gehen muss. Ich versuche, einige ausgezeichnete Werkzeuge zu lernen (bis jetzt ist Pandas mein Favorit), aber ich gehe davon aus, dass ich zuerst einen Algorithmus implementieren muss, damit diese Werkzeuge mit den Daten so umgehen können, wie ich es brauche.
Wenn es hilft, werde ich meinen Python-Code (Quelle) veröffentlichen.
Aktualisierung Folgende sind mein Code. Ich habe mehrere Zeilen weggelassen (wie try/catch block für ungültigen Dateipfad/-format, Typ Conversion Error Handling usw.). Ich habe den Code ein bisschen angepasst, um für 5 Sekunden Fenster zu arbeiten.
Im Anschluss an die Box Klasse
from datetime import datetime
from time import mktime
class Box(object):
""" Box model """
def __init__(self,data_set):
self.date = data_set[0]
self.timestamp = self.__get_time()
self.id = data_set[1]
self.length = float(data_set[2])
self.width = float(data_set[3])
self.height = float(data_set[4])
self.weight = int(data_set[5])
self.volume = self.__get_volume()
def __get_time(self):
""" convert from date string to unix-timestamp """
str_format = '%Y-%m-%d %H:%M:%S'
t_tuple = datetime.strptime(self.date, str_format).timetuple()
return mktime(t_tuple)
def __get_volume(self):
""" calculate volume of the box """
return (self.length * self.width * self.height)
Es folgt das eigentliche Programm den Vergleich durchführen. Ich habe die Utility-Datei und die main.py-Datei zur Vereinfachung zusammengefasst.
from csv import reader
from io import open as open_file
from os import path
from sys import argv, exit
from time import time
# custom lib
from Box import Box
def main():
file_name = str.strip(argv[1])
boxes_5s = []
diff = 0
similar_boxes = []
for row in get_file(file_name):
if row:
box = Box(row)
if len(boxes_5s) > 0:
diff = box.timestamp - boxes_5s[0].timestamp
if diff < 6:
boxes_5s.append(box)
else:
similar_boxes += get_similar(boxes_5s)
del boxes_5s[0] # remove the oldest box
boxes_5s.append(box)
else:
boxes_5s.append(box)
print(similar_boxes)
def get_file(file_name):
""" open and return csv file pointer line by line """
with open_file(file_name,'rb') as f:
header = f.readline()
print(header)
rows = reader(f, delimiter=';')
for r in rows:
yield r
else:
yield ''
def get_similar(box_list):
""" compare boxes for similar volume """
num_boxes = len(box_list)
similar_boxes = []
record_str = "Box#{} Volm:{} and #{} Volm:{}"
for i in xrange(num_boxes):
box_1 = box_list[i]
for j in xrange(i+1, num_boxes):
box_2 = box_list[j]
vol_diff = abs((box_1.volume - box_2.volume)/box_1.volume) <= 0.1
if vol_diff: similar_boxes.append(record_str.format(box_1.id,box_1.volume,box_2.id, box_2.volume))
return similar_boxes
if __name__ == "__main__":
main()
Vielen Dank.
sollten Sie wahrscheinlich zuerst bestellen und dann finden Sie die ähnlichen Felder – armonge
es hilft. Siehe [Erstellen eines minimalen, vollständigen und überprüfbaren Beispiels] (http://stackoverflow.com/help/mcve) – rll
Es tut mir leid für die vage Natur meiner Frage, ich werde später etwas Code veröffentlichen, wenn ich zurück bin Zuhause –