繁体   English   中英

Python 中的 TSP:在随机数据点的代码中导入 .csv 文件

[英]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

你可以让CityDatenpunkt继承,并在那里添加你想要的任何专业。 由于复数在__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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM