Seite 1 von 1

MapReduce

Verfasst: Freitag 10. Dezember 2021, 21:20
von phykka
Hallo zusammen,

ich möchte eine python-Datei für einen MR-Jobs erstellen und habe dazu folgende csv Datei:
Timestamp,Produktname,Produkt_ID,Station1,Transport12,Station2,Transport23,Station3,Transport34,Station4,Transport45,Station5
2022-01-31 05:43:48.259893,Baseball,140499318896400,2.027,1.315,6.909,1.298,-4.039,0.9,1.344,0.972,10.031
2022-01-31 05:53:50.119893,Baseball,140499318897424,0.959,1.676,7.695,1.029,9.518,0.942,1.488,0.977,5.518
2022-01-31 05:59:21.199893,Baseball,140499318897200,3.528,0.788,10.93,1.855,8.214,0.702,-0.141,1.426,5.294
2022-01-31 06:04:38.839893,Baseball,140499318896400,3.201,1.755,5.46,0.422,6.667,0.567,1.108,0.628,2.827
2022-01-31 06:07:28.459893,Baseball,140499318897424,4.001,0.917,7.239,1.363,4.586,0.385,0.417,1.182,5.008
2022-01-31 06:12:28.939893,Baseball,140499318897200,1.418,0.611,6.102,0.625,2.436,1.334,0.865,1.031,3.235
2022-01-31 06:15:43.039893,Baseball,140499318896400,3.918,0.641,6.925,1.271,9.658,0.481,0.951,0.678,3.666
Ziel ist die Zeiten von Station1 bis Station5 zu addieren und zusammen mit dem Produktnamen (Produktname ist immer gleich) auszugeben.

Mein bisheriger Code:

Code: Alles auswählen

from mrjob.job import MRJob
from mrjob.step import MRStep

class Bearbeitungszeit(MRJob):

    def steps(self):
        step_1 = MRStep(mapper=self.zaehle_bearbeitungszeit)
        steps = [step_1]
        return steps

    def zaehle_bearbeitungszeit(self, _,value):
        (Timestamp,Produktname,Produkt_ID,Station1,Transport12,Station2,Transport23,Station3,Transport34,Station4,Transport45,Station5) = value.split(",")
        Nettobearbeitungszeit= Station1, Station2, Station3, Station4, Station5
        yield Produktname,Nettobearbeitungszeit

    pass

if __name__ == "__main__":
    Bearbeitungszeit.run()
Das Ergebnis:

Code: Alles auswählen

"Baseball"      ["2.027", "6.909", "-4.039", "1.344", "10.031"]
"Baseball"      ["0.959", "7.695", "9.518", "1.488", "5.518"]
"Baseball"      ["3.528", "10.93", "8.214", "-0.141", "5.294"]
"Baseball"      ["3.201", "5.46", "6.667", "1.108", "2.827"]
"Baseball"      ["4.001", "7.239", "4.586", "0.417", "5.008"]
"Baseball"      ["1.418", "6.102", "2.436", "0.865", "3.235"]
"Baseball"      ["3.918", "6.925", "9.658", "0.951", "3.666"]
Leider lassen sich die einzelnen Zahlen nicht addieren, da sie alle in einem Tupel sind.

Weiß jemand, wie sich die Zahlen / Tupel umwandeln lassen, damit sie addiert werden können und am Ende nur noch ein Wert existiert?

Vielen Dank vorab!

Re: MapReduce

Verfasst: Freitag 10. Dezember 2021, 21:35
von loggik
Wenn ich das richtig sehe sind das alles Strings in dem Tuple. Du musst dir also erstmal die Frage stellen wie kann ich aus den ganzen Strings float machen.
Dafür kannst du mit for über das Tuple iterieren:

Code: Alles auswählen

result = 0
for item in my_tuple:
    result += float(item)
Wären die Werte in deinem Tuple schon von Anfang an vom Typ float, dann brauchst du nur sum()

Code: Alles auswählen

sum(my_tuple)

Re: MapReduce

Verfasst: Freitag 10. Dezember 2021, 21:48
von phykka

Code: Alles auswählen

from mrjob.job import MRJob
from mrjob.step import MRStep

class Bearbeitungszeit(MRJob):

    def steps(self):
        step_1 = MRStep(mapper=self.zaehle_bearbeitungszeit)
        steps = [step_1]
        return steps

    def zaehle_bearbeitungszeit(self, _,value):
        (Timestamp,Produktname,Produkt_ID,Station1,Transport12,Station2,Transport23,Station3,Transport34,Station4,Transport45,Station5) = value.split(",")
        Nettobearbeitungszeit= (Station1, Station2, Station3, Station4, Station5)
        result = 0
        for item in Nettobearbeitungszeit:
            result += float(item)
        yield Produktname,Nettobearbeitungszeit

    pass

if __name__ == "__main__":
    Bearbeitungszeit.run()
vielen Dank! Ich habe es mit eingebaut aber leider erzeugt das erneut eine Fehlermeldung:

Code: Alles auswählen

    result += float(item)
ValueError: could not convert string to float: 'Station1'

Re: MapReduce

Verfasst: Freitag 10. Dezember 2021, 21:56
von loggik
Kann es sein, dass die erste Zeile deiner csv-Datei mit eingelesen wird? (Das kann ich anhand deines codes nicht erkennen)

Ansonsten sagen die Fehlermeldungen bei Python sehr genau was schief gelaufen ist: In deinem Fall hat Python versucht den String "Station1" in eine float zu casten, was nicht funktioniert.

In der jetzigen Form wird zwar result berechnet aber nicht zurückgegeben, das wirst du auch noch überarbeiten müssen.

Re: MapReduce

Verfasst: Freitag 10. Dezember 2021, 22:10
von phykka
Danke! :) jetzt funktioniert es

Re: MapReduce

Verfasst: Freitag 10. Dezember 2021, 22:39
von karolus
Hallo
Das geht bestimmt noch schöner, aber ich hab mich auch nicht lange damit aufgehalten:

Code: Alles auswählen

from pandas import read_csv

frame = read_csv("jobs.csv")
stations = frame.T[3::2].T
print(stations)
print(stations.sum())
print(sum(stations.sum()))
gibt folgendes aus:

Code: Alles auswählen


  Station1 Station2 Station3 Station4 Station5
0    2.027    6.909   -4.039    1.344   10.031
1    0.959    7.695    9.518    1.488    5.518
2    3.528    10.93    8.214   -0.141    5.294
3    3.201     5.46    6.667    1.108    2.827
4    4.001    7.239    4.586    0.417    5.008
5    1.418    6.102    2.436    0.865    3.235
6    3.918    6.925    9.658    0.951    3.666
Station1    19.052
Station2     51.26
Station3     37.04
Station4     6.032
Station5    35.579
dtype: object
148.96299999999997

Re: MapReduce

Verfasst: Samstag 11. Dezember 2021, 09:28
von DeaD_EyE
Was ich immer so schade finde, ist die exzessive Nutzung von numpy, pandas oder anderen Bibliotheken, und das fehlende Verständnis, wie man etwas ausschließlich mit der Standardlib von Python macht. Hier mal ein Beispiel ohne pandas.

Code: Alles auswählen

import io
import csv
from collections import namedtuple
from datetime import datetime


data = """Timestamp,Produktname,Produkt_ID,Station1,Transport12,Station2,Transport23,Station3,Transport34,Station4,Transport45,Station5
2022-01-31 05:43:48.259893,Baseball,140499318896400,2.027,1.315,6.909,1.298,-4.039,0.9,1.344,0.972,10.031
2022-01-31 05:53:50.119893,Baseball,140499318897424,0.959,1.676,7.695,1.029,9.518,0.942,1.488,0.977,5.518
2022-01-31 05:59:21.199893,Baseball,140499318897200,3.528,0.788,10.93,1.855,8.214,0.702,-0.141,1.426,5.294
2022-01-31 06:04:38.839893,Baseball,140499318896400,3.201,1.755,5.46,0.422,6.667,0.567,1.108,0.628,2.827
2022-01-31 06:07:28.459893,Baseball,140499318897424,4.001,0.917,7.239,1.363,4.586,0.385,0.417,1.182,5.008
2022-01-31 06:12:28.939893,Baseball,140499318897200,1.418,0.611,6.102,0.625,2.436,1.334,0.865,1.031,3.235
2022-01-31 06:15:43.039893,Baseball,140499318896400,3.918,0.641,6.925,1.271,9.658,0.481,0.951,0.678,3.666"""


reader = csv.reader(io.StringIO(data))
header = next(reader)
header.append("Summe")

Row = namedtuple("Row", header)
results = []

for ts, name, pid, *stations in reader:
    value = round(sum(map(float, stations)), 3)
    ts = datetime.strptime(ts, "%Y-%m-%d %H:%M:%S.%f")
    print(ts, name, pid, *stations, value)
    results.append(Row(ts, name, pid, *stations, value))
Das ist jetzt keine besondere Anstrengung für mich, da ich die stdlib fast auswendig kenne. Hier und dort vergesse ich mal bestimmte Features, aber bei ständiger Nutzung bleibt das Wichtigste im Kopf.
Bei dem Beispiel kommt z.B. PEP 3132 zur Anwendung: https://www.python.org/dev/peps/pep-3132/

Lernt man so was, wenn man pandas schwarze Magie nutzt? Nein.

Re: MapReduce

Verfasst: Samstag 11. Dezember 2021, 10:25
von snafu
@DeaD_EyE
Stellt sich halt nur die Frage, was daran falsch sein soll, Werkzeuge zu benutzen, wenn diese zur Verfügung stehen. Im Rahmen eines Python-Kurses, der noch nicht pandas behandelt hat, finde ich deine Lösung sinniger, weil der Lerneffekt größer ist. Im täglichen Gebrauch würde ich aber auf jeden Fall zur pandas-Lösung tendieren, da sie deutlich kürzer und für die meisten wohl auch schneller zu implementieren ist.

Re: MapReduce

Verfasst: Samstag 11. Dezember 2021, 11:11
von __blackjack__
Wobei da jetzt soweit ich das sehe in `stations` auch die "Transport*"-Spalten enthalten sind und mit aufsummiert werden‽ Ich vermute das war nicht gewünscht/ist falsch.

Kann man in der Pandas-Lösung aber auch leicht übersehen. Da hätte ich statt magischem Slicing mit Schrittweite wahrscheinlich die Spalten nach danach selektiert ob die mit "Station" anfangen. Ist für den menschlichen Leser besser verständlich und wahrscheinlich auch sicherer.

Re: MapReduce

Verfasst: Samstag 11. Dezember 2021, 14:48
von karolus
Ich kenne die Stdlib nicht "fast auswendig" … auch die "schwarzre Magie" von pandas ist erstmal gewöhnungsbedürftig, aber ich habe halt nicht übersehen das der OP offenbar nur an den Station.* -spalten interressiert ist.
Hier eine Schönere Version:

Code: Alles auswählen

import pandas as pd 

frame = pd.read_csv("jobs.csv")
is_station = frame.columns.str.startswith('Station')
stations = frame.loc[:, is_station]
print(stations,"\n")
print(stations.sum(),"\n")
print(sum(stations.sum()))

Re: MapReduce

Verfasst: Samstag 11. Dezember 2021, 19:58
von DeaD_EyE
__blackjack__ hat geschrieben: Samstag 11. Dezember 2021, 11:11 Wobei da jetzt soweit ich das sehe in `stations` auch die "Transport*"-Spalten enthalten sind und mit aufsummiert werden‽ Ich vermute das war nicht gewünscht/ist falsch.
Ja, das könnte man noch mit slicing lösen.
2 Zeilen Code mehr.

Kann man in der Pandas-Lösung aber auch leicht übersehen. Da hätte ich statt magischem Slicing mit Schrittweite wahrscheinlich die Spalten nach danach selektiert ob die mit "Station" anfangen. Ist für den menschlichen Leser besser verständlich und wahrscheinlich auch sicherer.
Alle wollen mit Pandas irgendwas an Daten verarbeiten, haben noch nicht einmal die Grundkonzepte des Slicings verstanden. Das führt dazu, dass die Anfänger nicht Python lernen, sondern Pandas. Mein Einwand richtet sich nicht gegen Pandas selbst, sondern die Art und Weise wie damit umgegangen wird. Ich fange doch auch nicht mit der Elektroinstallation in einem Haus an, wenn das Haus noch gar nicht steht.

Re: MapReduce

Verfasst: Samstag 11. Dezember 2021, 20:07
von Sirius3
@DeaD_EyE: viele wollen nicht programmieren, sondern Daten analysieren, und dazu muß man meist nur Pandas beherrschen. Die einen bauen Häuser, andere machen Elektroinstallation. Daran ist nichts auszusetzen.

Re: MapReduce

Verfasst: Dienstag 14. Dezember 2021, 07:33
von Zizibee
@DeaD_EyE: Aber ist das nicht auch ein bischen eine Eigenart von Python, dass man sich nicht lange überlegt wie etwas sinnvoll und gut zu programmieren wäre, sondern dass man dafür ein Modul sucht, welches das für einen löst?
Eine Eigenschaft, die Leute die nicht gerne programmieren mögen und worüber C Programmierer etwas die Nase rümpfen :wink:
Da ist zumindest mein Eindruck...