Minimaler Abstand

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Hallo Leute,
wir blutigen Anfänger brauchen eure erfahrene Hilfe.
Wir haben eine Tabelle (csv-Format) mit Wetter-Daten (wir lassen es derzeit zeilenweise einlesen). Die Spaltenüberschriften bestehen aus verschiedenen Temperaturen. Eine vorher berechnete Durchschnittstemperatur soll mit den Überschrifts-Temperaturen verglichen werden und der minimalste Abstand berechnet werden. Wir benötigen die Temperatur, welche am nähsten an der Durchschnittstemperatur liegt. Wie kann man den minimalsten Abstand berechnen???

Bsp:

Code: Alles auswählen

           15°C        17°C     19°C        20°C
T1         ....
T2         ....
T3         ....
Durchschnittstemp. = 16,8

(Wenn die Durchschnittstemperatur dazwischen liegt, soll die niedrigere verwendet werden.)

Im voraus schon mal vielen vielen Dank für eure Hilfe :)
Benutzeravatar
sparrow
User
Beiträge: 4144
Registriert: Freitag 17. April 2009, 10:28

Geh die Liste der Temperaturen durch, zieh die Temperatur in der Überschrift ab.
Falls das Ergebnis negativ ist, wandele es in ein positives Ergebnis.
Wenn das Ergebnis kleiner als die zuletzt gemerkte kleinste Abweichung ist, merke die die aktuelle Temperatur als die mit er kleinsten Abweichung und die kleinste Abweichung.
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Ich habe etwas vergessen. Die Temperaturen stehen nur in den Spaltenüberschriften. Die Tabelle selbst besteht aus anderen Werten. Ich müsste also nur die Spaltenüberschrift, also diese Zeile durch gehen, dann entscheiden welche Temp. der Durchschnittstemp. am nächsten ist. Dann muss ich mit der betreffenden Spalte weiter rechnen.

(Danke für die schnelle Antwort!)

LG
BlackJack

@Haze91: Na dann gehst Du halt diese Zeile durch und findest den geringsten Abstand. Wenn Du die Spaltennummer brauchst, dann kannst Du mit `enumerate()` Tupel aus Spaltenindex und Temperaturwert erstellen und dann mit der `min()`-Funktion und dem `key`-Argument und einer passenden Funktion das nach Deinen Kriterien ”kleinste” Tupel auswählen. Eine anonyme Funktion (``lambda``-Schlüsselwort) wäre da praktisch und man braucht noch die `abs()`-Funktion um den absoluten Wert der Differenz einfach berechnen zu können.
BlackJack

Code: Alles auswählen

import io


def parse_header(line):
    return (float(t.strip(u'C°')) for t in line.split())


def get_index_of_closest(reference_temperature, temperatures):
    return min(
        enumerate(temperatures), key=lambda t: abs(t[1] - reference_temperature)
    )[0]


def main():
    reference_temperature = 16.8
    with io.open('test.txt', 'r', encoding='utf8') as lines:
        line = next(lines)
    temperatures = parse_header(line)
    closest_index = get_index_of_closest(reference_temperature, temperatures)
    print(closest_index)


if __name__ == '__main__':
    main()
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Hey.
Ich habe den Quellcode so übernommen, leider hat es nicht geklappt.
Ich habe ein Bild hochgeladen auf dem der Quellcode, die Terminalausgabe und die Tabelle zu sehen sind.
http://www.bilder-upload.eu/show.php?fi ... 451700.png

Welche Änderung muss ich noch vornehmen?
Danke für eure Hilfe :)
BlackJack

@Haze91: Ich habe halt Quelltext geschrieben der von einer Eingabedatei ausgeht die so wie in Deinem Beitrag aussieht. Wenn Deine Datei eigentlich ganz anders aussieht, kann ich das ja schlecht erraten. :roll:
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Die Tabelle im Betrag war nur schematisch dargestellt. Sorry, für die Unklarheit.

Wie können wir den Quellcode ändern, um den Fehler (ValueError: Could not convert string to float) zu beheben?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hazei91: Du mußt halt die Zeilen der Datei entsprechend ihres Trennzeichens in die einzelnen Zellen aufteilen. BlackJack hat das anhand des Beispiels an Leerraum gemacht, Du hast ja anscheinend statt dessen ein Komma.
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Ok, wir haben jetzt alles komplett umstrukturiert und trotzdem hängts. so sieht ein Teil unseres Quellcodes bisher aus:

Code: Alles auswählen

 #!/usr/bin/python3.4
# -*- coding: utf8 -*-

richtig1 = False
while(richtig1 == False):
	art = input("Eingabe: ")
	if art == 1:
		liste = [15.8,20.7,23.3]
		richtig1 = True
	elif art == 2:
		liste = [15,17,19,20,21,22,25,28,30,34]
		richtig1 = True
	elif art == 3:
		liste = [7.5,10,12.5,15,17.5,20,22.5,25,27.5,30,32.5]		
		richtig1 = True
	else:			
		print("Fehler, falsche Eingabe. Bitte versuchen Sie es erneut!")
temp = 18
i = 0
while i < len(liste):
	for i in liste:
		zahl = abs(temp-liste[i])
		zahl_neu = abs(temp-liste[i+1])	
		if zahl >= zahl_neu:
			print zahl_neu
		else:
			print zahl
		i = i + 1
Die Variable "Temp" ist der Wert, welcher mit einer der 3 Listen (je nach Eingabe) verglichen werden soll. Es soll der Wert zurück gegeben werden, der dem Wert "Temp" am nähsten ist. Sollte "temp" dazwischen liegen, so soll der niedrigere Wert ausgegeben werden bzw. müssen wir auf die Stelle (i) in der Liste zugreifen können.

Es sollte "i" zurück gegeben werden, da wir "i" für weitere Berechnungen benötigen.

Derzeit kommt der Fehler "list index out of range"
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Haze91: while ist keine Funktion, was sollen also die Klammern? input liefert Strings, die können also nie gleich irgendeiner Zahl sein. Ach das ist gar kein Python 3, obwohl es in der Shebang-Zeile steht?? Dann soltest Du sowieso rawinput nehmen. Sowas würde man auch mit einem Wörterbuch statt einer if-Kaskade lösen.
Eigentlich sollte da ein Type-Error kommen, da 15.8 kein gültiger Listenindex ist. Das mit der while und for-Schleife mit der selben Laufvariable ist auch mehr als seltsam.
Schonmal was von bisect gehört?

Code: Alles auswählen

idx = bisect.bisect(liste, temp)
print(liste[idx])
BlackJack

@Haze91: Warum geht denn hier die `get_index_of_closest()` von oben nicht? Ansonsten ist das von Sirius3 vorgeschlagene `bisect`-Modul auch eine gute Idee wenn die Liste mit den Temperaturen sortiert vorliegt.
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Die Methode funktioniert!!! :) Danke :)

Allerdings haben wir noch ein Problem: es wird immer der größere anstatt der kleinere ausgegeben. Also wenn 18 mit 17 und 19 verglichen werden soll, sollte 17 ausgegeben werden. Derzeit wird 19 ausgegeben.

@Sirius3: die Klammern haben wir entfernt. Das mit dem rawinput hat bei uns nicht so richtig funktioniert. Aber es funktioniert so wie es da steht :K

@BlackJack: bei dem get_index_of_closest() kam immer ein Fehler :K
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

das ganze nochmal als Komplettpaket:

Code: Alles auswählen

from bisect import bisect

TEMPERATURE_LISTS = {
    1: [15.8,20.7,23.3],
    2: [15,17,19,20,21,22,25,28,30,34],
    3: [7.5,10,12.5,15,17.5,20,22.5,25,27.5,30,32.5],
}

def input_temperature_list():
    while True:
        try:
            return TEMPERATURE_LISTS[int(raw_input("Eingabe"))]
        except (ValueError, KeyError):
            print "Fehler, falsche Eingabe. Bitte versuchen Sie es erneut!"

def main():
    temperatures = input_temperature_list()

    temperature = 18
    idx = max(0, bisect(temperatures, temperature) - 1)
    print temperatures[idx]

if __name__ == '__main__':
    main()
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Wenn wir das so versuchen auszuführen, kommt der Fehler: "TypeError: 'module' object is not callable" :?:
BlackJack

@Haze91: Das glaube ich nicht. Ich bin mir sicher Euer ``import`` sieht dann anders aus.
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Upps, wir hatten einen Tippfehler :shock:

Danke für die schnelle Hilfe :)

Was müssen wir ändern, wenn wir "idx" auch außerhalb der Funktion verwenden wollen?
BlackJack

@Haze91: Falls ausserhalb auf Modulebene meint: Gar nichts, das solltet ihr sein lassen. In eine andere Funktion bekommt man Werte in dem man sie beim Aufruf als Argument übergibt.
Haze91
User
Beiträge: 12
Registriert: Donnerstag 3. September 2015, 10:17

Wir müssen das "idx" aus der Methode weiter unten bei der if-Anweisung verwenden.

Auszug aus unserem Programm:

Code: Alles auswählen

def main():
	temperatures = temperaturen
	idx = max(0, bisect(temperatures, temp) - 1)
	 
if __name__ == '__main__':
	main()

if stadium == "a":
	miniS = ei[idx]
	maxiS = ei[idx]
BlackJack

@Haze91: Eben genau das ist nicht das was ihr müsst. So ein Code hat auf Modulebene nichts zu suchen. Dort sollten nur Konstanten, Funktionen, und Klassen definiert werden. Das Hauptprogramm gehört in eine Funktion. Die heisst üblicherweise `main()`. Hier ist also nicht die Frage wie man das `idx` aus der `main()`-Funktion bekommt, sondern warum der andere Code nicht in der `main()`-Funktion steht.
Antworten