[英]TSP in Python: Importing a .csv-file in code for randomized data points
在編碼方面,我是個菜鳥。 我目前正在嘗試為旅行推銷員問題編寫解決方案。 我已經找到了一組隨機值的功能代碼(如下所示或https://nbviewer.jupyter.org/url/norvig.com/ipython/TSP.ipynb#Random-Sets-of-Cities )。 現在我想使用我創建的 a.csv 文件中的數據,其中包含坐標系中城市的數據(x 和 y 值)。 但是我無法弄清楚我必須在代碼中更改什么。
我嘗試將 Cities() function 的定義更改為return frozenset(City() for row in csv.reader(staedtekoordinaten.csv, delimiter=";")
這可能是一個非常愚蠢的問題,但如果有人可以幫助我,我將不勝感激......提前致謝!
import matplotlib.pyplot as plt
import random
import time
import itertools
import urllib
import csv
import functools
from statistics import mean, stdev
def alle_touren_tsp(cities):
# Erstelle eine Auflistung aller möglichen auszuführenden Touren. Aus dieser Liste
# kann später eine Auswahl per "min" Funktion getroffen werden, die die kürzeste Route darstellt.
return minimale_tour(alle_touren(cities))
def minimale_tour(tours):
# Definiere Funktion zur Auswahl der kürzesten Tour.
return min(tours, key=laenge_tour) # aus der Sammlung "touren" minimiere ELement "distanz_tour"
#Verbesserung - Redundante Touren werden vermieden (reduziert Rechenaufwand)
def alle_touren(cities):
# Gibt List mit Touren aus mit Permutation von Städten, alle permutationen starten jedoch mit
# derselben Stadt (verhindert Redundanzen)
start = first(cities)
return [[start] + Tour(rest)
for rest in itertools.permutations(cities - {start})]
def first(collection):
#Iteration über die collection, Ausgabe des jeweils ersten Elements
return next(iter(collection))
Tour = list # Tours are implemented as lists of cities
def laenge_tour(tour):
# Gesamtsumme einer Tour.
# Addiert die gelaufenen Teildistanzen zwischen zwei Datenpunkten (= locations)
return sum(distance(tour[i], tour[i - 1]) # für i=0 wird i-1 der letzte Datenpunkt
for i in range(len(tour)))
# Für alle Elemente in tour (Anzahl = len(tour)) wird die Distanz von der vorherigen Location (i-1)
# zur aktuellen (i) summiert)
# Lösung mit Subclass von Complex - Jeder Datenpunkt (also jeder Ort) wird mit zwei Koordinaten gespeichert,
# der Einfachheit halber im komplexen Zahlenraum (dort hat jeder Punkt generell zwei Koordinaten)
class Datenpunkt(complex):
x = property(lambda p: p.real)
y = property(lambda p: p.imag)
City = Datenpunkt
def distance(A, B):
# Definiert die Distanz "zu laufende Länge" zwischen den Punkten A und B => Euklidische Distanz
return abs(A - B)
# Testdatenpunkt: Randomized Cities mit Seed 42
def Cities(n, width=900, height=600, seed=42):
# Set aus n Datenpunkten mit randomized Koordinaten, dargestellt in width x height (900x600 weil Python-Standard)
random.seed(seed * n)
return frozenset(City(random.randrange(width), random.randrange(height))
# frozenset, damit kein Algorithmus einfach Datenpunkte löscht
# (i. S. v. der kürzeste Weg wäre, erst gar keinen Weg zu laufen)
for c in range(n))
alle_touren_tsp(Cities(8))
def plot_tour(tour):
# "Plot the cities as circles and the tour as lines between them."
plot_lines(list(tour) + [tour[0]])
def plot_lines(points, style='bo-'):
# "Plot lines to connect a series of points."
plt.plot([p.x for p in points], [p.y for p in points], style)
plt.axis('scaled');
plt.axis('off')
plot_tour(alle_touren_tsp(Cities(8)))
def plot_tsp(algorithm, cities):
# "Apply a TSP algorithm to cities, plot the resulting tour, and print information."
# Find the solution and time how long it takes
t0 = time.process_time()
tour = algorithm(cities)
t1 = time.process_time()
assert valid_tour(tour, cities)
plot_tour(tour);
plt.show()
print("{} city tour with length {:.1f} in {:.3f} secs for {}"
.format(len(tour), laenge_tour(tour), t1 - t0, algorithm.__name__))
def valid_tour(tour, cities):
# "Is tour a valid tour for these cities?"
return set(tour) == set(cities) and len(tour) == len(cities)
plot_tsp(alle_touren_tsp, Cities(8))
至於新代碼(如果我理解正確的話:
import csv
# Lösung mit Subclass von Complex - Jeder Datenpunkt (also jeder Ort) wird mit zwei Koordinaten gespeichert,
# der Einfachheit halber im komplexen Zahlenraum (dort hat jeder Punkt generell zwei Koordinaten)
class Datenpunkt(complex):
x = property(lambda p: p.real)
y = property(lambda p: p.imag)
class City(Datenpunkt):
# this is a subclass of `complex` which sets itself up in `__new__`
def __new__(cls, x, y, name):
self = super().__new__(cls, float(x), float(y))
self.name = name
return self
def __str__(self):
return "{} {}".format(super().__str__(), self.name)
def __repr__(self):
return str(self)
@classmethod
def from_csv(cls, row):
"""Create class from CSV row. Row is assumed to be a collection with
index 0 and 1 being the coordinates of interest."""
return cls(*row[0:3])
def Cities(filename):
with open(filename, newline='') as fp:
return frozenset(City.from_csv(row) for row in csv.reader(fp, delimiter=";"))
print(Cities("testfile.csv"))
這給出了錯誤: Traceback(最近一次調用最后一次):
File "filepath/Test.py", line 35, in <module>
print(Cities("testfile.csv"))
File "filepath/Test.py", line 34, in Cities
return frozenset(City.from_csv(row) for row in csv.reader(fp,
delimiter=";"))
File "filepath/Test.py", line 34, in <genexpr>
return frozenset(City.from_csv(row) for row in csv.reader(fp,
delimiter=";"))
File "filepath/Test.py", line 29, in from_csv
return cls(*row[0:3])
File "filepath/Test.py", line 15, in __new__
self = super().__new__(cls, float(x), float(y))
ValueError: could not convert string to float: 'x'
Process finished with exit code 1
根據您的想法打印的行是:
b'\xef\xbb\xbfx;y;name\r\n'b'0;0;Duisburg\r\n'
b'455,56;120,87;Berlin\r\n'
b'218,86;235,59;Hamburg\r\n'
b'345,6;-366,75;Muenchen\r\n'
b'13,97;-55,24;Koeln\r\n'
b'135,12;-147,2;Frankfurt\r\n'
b'190,25;-13,17;Kassel\r\n'
b'297,02;-51,3;Erfurt\r\n
你可以讓City
從Datenpunkt
繼承,並在那里添加你想要的任何專業。 由於復數在__new__
方法中自行初始化,因此如果您的 object 構造參數不同於complex
,您必須自己實現。 我決定添加城市名稱和允許坐標作為字符串作為您可以執行的示例。
我還添加了一個了解 csv 行格式的 class 方法。 您可能會爭辯說,它是City
的一個相當狹窄的專業化工廠,而這家工廠應該是外部 function,但是,嘿,我這樣做只是為了顯示選項。
此示例運行,您將其添加到您認為合適的代碼中。
import csv
# Lösung mit Subclass von Complex - Jeder Datenpunkt (also jeder Ort) wird mit zwei Koordinaten gespeichert,
# der Einfachheit halber im komplexen Zahlenraum (dort hat jeder Punkt generell zwei Koordinaten)
class Datenpunkt(complex):
x = property(lambda p: p.real)
y = property(lambda p: p.imag)
class City(Datenpunkt):
# this is a subclass of `complex` which sets itself up in `__new__`
def __new__(cls, x, y, name):
self = super().__new__(cls, float(x), float(y))
self.name = name
return self
def __str__(self):
return "{} {}".format(super().__str__(), self.name)
def __repr__(self):
return str(self)
@classmethod
def from_csv(cls, row):
"""Create class from CSV row. Row is assumed to be a collection with
index 0 and 1 being the coordinates of interest."""
return cls(*row[0:3])
def Cities(filename):
with open(filename, newline='') as fp:
return frozenset(City.from_csv(row) for row in csv.reader(fp, delimiter=";"))
# test
print(City.from_csv(["111", "222", "Far City"]))
open('testcities.csv', 'w').write("""\
111;222;Far City
4.55;66;Near City
""")
cities = Cities('testcities.csv')
print(cities)
for city in cities:
print("{}: {}, {}".format(city.name, city.x, city.y))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.