Alle Programme können von hier heruntergeladen werden. |
Problembeschreibung |
Oft hat man Datensammlungen mit Datensätzen, bei denen der Wert eines bestimmten Zielattributs mit den Werten anderer Attribute zusammenhängt. Es stellt sich die Frage, welches dieser Attribute den überwiegenden Einfluss aus das Zielattribut hat. Als wichtiges Beispiel untersucht man, inwiefern sich die Wetterlage zu einer bestimmten Zeit, sagen wir heute um Mittag, auf Grund der Wetterbeobachtungen am frühen Morgen voraussagen lässt. Der Einfachheit betrachten wir als Zielattribut nur die Wetterwerte Schneefall (snow), Regenfall (rain), Sonnig (sun). Als beobachtete Wetterattribute wählen wir Wolken (clouds) mit den Werten bedeckt (overcast), bewölkt (cloudy), klar (clear) Das Trainings-Set besteht aus nur 20 Datensätzen in der Datei weather.csv, die von hier heruntergeladen werden kann.
Beim OneR-Algorithmus untersucht man bei jedem Attribut (Wolken, Temperatur, Luftfeuchtigkeit, Wind) einzeln, ob man damit eine möglichst gute Wettervoraussage machen kann. (Daher der Name One-Rule, abgekürzt OneR.) Für jedes Attribut bestimmt man eine Fehlerquote ein und wählt dann am Schluss für die Wettervoraussage dasjenige Attribut mit der kleinsten Fehlerquote. |
Voraussage mit einem einzelnen Attribut |
Wir wählen ein bestimmtes Attribut aus, beispielsweise die Luftfeuchtigkeit und bestimmen dann für jeden Wahl des Wert des Attributs tief, normal, hoch die Zahl der Instanzen für jede Wetterlage. Anders gesagt, wir untersuchen für eine tiefe, dann für eine normale und dann für eine hohe Luftfeuchtigkeit wie oft dies zu im Trainings-Set zu Sonnig, Regenfall, Schneefall geführt hat. Es ist vorteilhaft, die Attribute mit ihren Werten in einem Dictionary attributes und die Häufigkeiten in einem Dictionary frequencies abzulegen. Programm: [►] # OneRule1.py Resultat: |
Fehlerquote |
Wenden wir für das Attribut Luftfeuchtigkeit das vorher herausgefundene Voraussagemodell mit der Regel: humidity low->sun, humidity normal->sun, hudinity high->rain an, so lässt sich eine Fehlerquote als Anzahl der Falschvorhersagen angeben. Für jeden Wert des Attributes lesen wir aus dem obigen Resultat die folgenden Werte heraus: humidity low->2, humidity normal->4, humidity high->3. Um diese Zahlen zu berechnen, ergänzen wir das vorherige Programm und ordnen als erstes durch Sortieren des Dictionaries die Wetterwerte in der Reihenfolge zunehmender Treffer an. Der Wert für das Voraussagemodell ist dann an 3. Stelle (index:2). Wir speichern ihn im Dictionary predictionRule. Die Fehlerwerte sammeln wir im Dictionary errorCount. Zuletzt ziehen wir noch Bilanz und schreiben die Summe der Fehler als Güte für das Voraussagemodell unter Benützung des gewählten Attributes (Luftfeuchtigkeit) aus. Programm: [►] # OneRule2.py dataFile = "weather.csv" attributes = {"Clouds":["overcast", "cloudy", "clear"], "Temperature":["cold", "mild", "hot"], "Humidity":["low", "normal", "high"], "Wind":["weak", "strong"]} attributeNames = ["Clouds", "Temperature", "Humidity", "Wind"] # targetValues: "sun", "rain", "snow" def loadData(fileName): try: fData = open(fileName, 'r') except: return [] out = [] for line in fData: line = line[:-1] # remove \n if len(line) == 0: # empty line continue li = [i for i in line.split(",")] out.append(li) fData.close() return out X = loadData(dataFile) attribute = "Humidity" predictionRule = {} errorCount = {} print "Considering attribute: '%s' now..." %(attribute) for value in attributes[attribute]: print " Statistics for attribute '%s' with value '%s':" \ %(attribute, value) frequencies = {"sun":0, "rain":0, "snow":0} k = X[0].index(attribute) # position of attribute for sample in X[1:]: if sample[k] == value: if sample[4] == "sun": frequencies["sun"] += 1 if sample[4] == "rain": frequencies["rain"] += 1 if sample[4] == "snow": frequencies["snow"] += 1 print " Frequency (number of instances): \ 'sun': %s, 'rain':, %s, 'snow': %s" \ %(frequencies["sun"], frequencies["rain"], frequencies["snow"]) # sort by dictionary value ratings = sorted(frequencies, key = frequencies.get) predictionRule[value] = ratings[2] errorCount[value] = frequencies[ratings[0]] + frequencies[ratings[1]] print "Prediction Rule:", predictionRule print "Error Count:", errorCount err = 0 for v in errorCount.values(): err += v print "Total error for prediction with attribute '%s': %d" \ %(attribute, err) Resultat: |
OneR-Analyse: Die Suche nach dem besten Attribut |
Bisher haben wird nur ein einzelnes Attribut betrachtet. Der OneR-Algorithmus definiert sich folgendermassen: Man suche nach dem Attribut mit dem kleinsten Fehler und wende für Vorhersagen nur die Regel dieses einen Attributs an. Damit wir alle Attribute gut durchlaufen können, verschieben wir den Code zur Bestimmung der Regel und des Fehlers in eine Funktion createRule(attribute). Am Schluss suchen wir nach dem Attribut mit dem kleinsten Fehler. Programm: [►] # OneRule3.py from operator import itemgetter dataFile = "weather.csv" attributes = {"Clouds":["overcast", "cloudy", "clear"], "Temperature":["cold", "mild", "hot"], "Humidity":["low", "normal", "high"], "Wind":["weak", "strong"]} attributeNames = ["Clouds", "Temperature", "Humidity", "Wind"] # targetValues: "sun", "rain", "snow" def loadData(fileName): try: fData = open(fileName, 'r') except: return [] out = [] for line in fData: line = line[:-1] # remove \n if len(line) == 0: # empty line continue li = [i for i in line.split(",")] out.append(li) fData.close() return out def createRule(attribute): predictionRule = {} errorCount = {} print "Considering attribute: '%s' now..." %(attribute) for value in attributes[attribute]: frequencies = {"sun":0, "rain":0, "snow":0} k = X[0].index(attribute) # position of attribute for sample in X[1:]: if sample[k] == value: if sample[4] == "sun": frequencies["sun"] += 1 if sample[4] == "rain": frequencies["rain"] += 1 if sample[4] == "snow": frequencies["snow"] += 1 # sort by dictionary value ratings = sorted(frequencies, key = frequencies.get) predictionRule[value] = ratings[2] errorCount[value] = frequencies[ratings[0]] + frequencies[ratings[1]] err = 0 for v in errorCount.values(): err += v return predictionRule, err X = loadData(dataFile) rules = {} errors = {} for attribute in attributeNames: rule, error = createRule(attribute) print "Rule", rule, "Error:", error rules[attribute] = rule errors[attribute] = error errors = sorted(errors, key = itemgetter(1)) bestAttribute = errors[0] print "\nResult of OneR Analysis:" print "Best attribute:", bestAttribute print "Rule:", rules[bestAttribute] Resultat: Result of OneR Analysis: |
Anwendung auf das Test-Set |
Schliesslich überprüfen wir die Voraussagegüte, indem wir die durch die OneR-Analyse gefundene Regel auf eine Datensammlung eines Test-Sets aus der Datei weathertest.csv anwenden. Diese enthält nur 6 Instanzen und kann von hier heruntergeladen werden. Programm: [►] # OneRule4.py from operator import itemgetter dataFile = "weather.csv" testFile = "weathertest.csv" attributes = {"Clouds":["overcast", "cloudy", "clear"], "Temperature":["cold", "mild", "hot"], "Humidity":["low", "normal", "high"], "Wind":["weak", "strong"]} attributeNames = ["Clouds", "Temperature", "Humidity", "Wind"] # targetValues: "sun", "rain", "snow" def loadData(fileName): try: fData = open(fileName, 'r') except: return [] out = [] for line in fData: line = line[:-1] # remove \n if len(line) == 0: # empty line continue li = [i for i in line.split(",")] out.append(li) fData.close() return out def createRule(attribute): predictionRule = {} errorCount = {} for value in attributes[attribute]: frequencies = {"sun":0, "rain":0, "snow":0} k = X[0].index(attribute) # position of attribute for sample in X[1:]: if sample[k] == value: if sample[4] == "sun": frequencies["sun"] += 1 if sample[4] == "rain": frequencies["rain"] += 1 if sample[4] == "snow": frequencies["snow"] += 1 # sort by dictionary value ratings = sorted(frequencies, key = frequencies.get) predictionRule[value] = ratings[2] errorCount[value] = frequencies[ratings[0]] + frequencies[ratings[1]] err = 0 for v in errorCount.values(): err += v return predictionRule, err X = loadData(dataFile) rules = {} errors = {} for attribute in attributeNames: rule, error = createRule(attribute) rules[attribute] = rule errors[attribute] = error errors = sorted(errors, key = itemgetter(1)) bestAttribute = errors[0] print "Result of OneR Analysis:" print "Best attribute:", bestAttribute print "Rule:", rules[bestAttribute] print "Applying now on test set..." Y = loadData(testFile) hit = 0 fail = 0 index = attributeNames.index(bestAttribute) for sample in Y: value = sample[index] prediction = rules[bestAttribute][value] if prediction == sample[4]: hit += 1 else: fail += 1 print "Success summary:" percent = 100 * hit / (hit + fail) print hit, "hits -->", int(percent + 0.5), "percent." Bemerkungen: |