pd.to_datetime Problem

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
SautaRoc
User
Beiträge: 48
Registriert: Donnerstag 20. September 2018, 13:18

Hallo,

Ich hole mir Daten aus der Zwischenablage in einen DataFrame:

Code: Alles auswählen

data = pd.read_clipboard(delimiter='\t')
data.columns = ['Datum', 'Zeit', 'B/S', 'Menge', 'Preis']

Ergebnis:

Code: Alles auswählen

      Datum           Zeit B/S  Menge    Preis
0   15Nov18  12:21:48:423    B      1  11414.0
1   15Nov18  12:21:28:278    B      1  11411.5
2   15Nov18  12:21:17:498    B      1  11410.5
3   15Nov18  12:21:17:495    B      1  11411.0

dann wandele ich in der Spalte 'Zeit' den String um, damit ich ihn in das Zeitformat umwandeln kann:

Code: Alles auswählen

data['Zeit'] = data['Zeit'].str.replace(':','.')
data['Zeit'] = data['Zeit'].str.replace('.',':',2)

Ergebnis:

Code: Alles auswählen

      Datum           Zeit B/S  Menge    Preis
0   15Nov18  12:21:48.423    B      1  11414.0
1   15Nov18  12:21:28.278    B      1  11411.5
2   15Nov18  12:21:17.498    B      1  11410.5
3   15Nov18  12:21:17.495    B      1  11411.0

(es wird also nur der letrzte Doppelpunkt duch einen Punkt ersetzt)


dann möchte ich die Spalte 'Zeit' in den Objekttyp 'datetime' umwandeln:

Code: Alles auswählen

data['Zeit'] = pd.to_datetime(data['Zeit']
Ergebnis:

Code: Alles auswählen

0   15Nov18 2018-12-01 12:21:48.423   B      1  11414.0
1   15Nov18 2018-12-01 12:21:28.278   B      1  11411.5
2   15Nov18 2018-12-01 12:21:17.498   B      1  11410.5
3   15Nov18 2018-12-01 12:21:17.495   B      1  11411.0

jetzt wurde das heutige Datum mit eingefügt, was leider falsch ist. Man könnte jetzt natürlich hingehen und vorher die Spalten Datum und Zeit kombinieren, damit das richtige Datum drinsteht, aber das ist auch nicht was ich wollte.

Ich habe zunächst probiert:

Code: Alles auswählen

data['Zeit'] = pd.to_datetime(data['Zeit'], format='%I:%M:%S')
Ergebnis:

Code: Alles auswählen

ValueError: unconverted data remains: .423 
Da dachte ich mir, ok du hast die Millisekunden nicht beachtet:

aber:

Code: Alles auswählen

data['Zeit'] = pd.to_datetime(data['Zeit'], format='%I:%M:%S.%f')
liefert: unconverted data remains:

dann dachte ich mir, ok der hat das Datum da reingepackt, nimms mal mit:

Code: Alles auswählen

data['Zeit'] = pd.to_datetime(data['Zeit'], format='%y-%m-%d %I:%M:%S.%f')
aber da kommt: ValueError: time data '12:21:48.423 ' does not match format '%y-%m-%d %I:%M:%S.%f' (match)


Jetzt gehen mir die Ideen aus. Kann mir bitte jemand weiterhelfen, danke?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Also erst einmal `to_datetime()` sagt ja schon irgendwie das da Datum *und* Zeit als Ergebnis heraus kommen. Wenn das Datum in den Daten nicht enthalten ist, dann wird das aktuelle Datum angenommen. An der Stelle solltest Du noch mal genau überlegen warum Du die Datumsspalte da nicht für verwenden willst.

Bei ``format='%I:%M:%S.%f'`` hast Du auch vorher die Sache mit dem Punkt gemacht? Oder müsstest Du dann das %f nicht vielleicht durch einen : trennen statt eines Punktes?

Das ``format='%y-%m-%d %I:%M:%S.%f'`` nicht geht, sollte ja eigentlich klar sein: In den 'Zeit'-Daten ist kein Datum enthalten, also kann man da logischerweise auch keine Platzhalter für in das Format packen.

Ist %I überhaupt richtig? Ich würde da ja ein %p mit im Format erwarten. Sonst ist %H das richtige für Stunden.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist das Problem, wenn man kaputte Datenformate hat, mit denen man arbeiten muß. Zum Glück bietet Pandas tausend Optionen, wie man Daten lesen kann.

Code: Alles auswählen

data = pandas.read_clipboard(delimiter='\t',
    header=None, index_col=['Datum', 'Zeit', 'B/S', 'Menge', 'Preis'],
    parse_dates=[['Datum', 'Zeit']], date_parser=lambda d:dateutil.parser.parse('.'.join(d.rsplit(':',1))))
SautaRoc
User
Beiträge: 48
Registriert: Donnerstag 20. September 2018, 13:18

also,

die strftime Referenz sagt

Code: Alles auswählen

%I    Hour (12-hour clock) as a zero-padded decimal number.    07
(http://strftime.org/). Das sollte also passen


ursprünglich ist in der Zeitspalte natürlich kein Datum drin, aber

Code: Alles auswählen

pd.to_datetime
hat ja nun ein Datum angenommen, daher ist es doch nun da?

den '.' hatte ich ja schon vorher in dem ursprünglichen String geändert, damit

Code: Alles auswählen

pd.to_datetime
überhaupt geht, da die ursprüngliche Version mit dem ':' nicht erkannt wird.

Ich werde jetzt mal versuchen die Datum Spalte mit der Zeitspalte zu kombinieren.

Code: Alles auswählen

data['DatumZeit'] = data['Datum']+' '+data['Zeit']
data['DatumZeit'] = pd.to_datetime(data['DatumZeit'])
data.drop(['Datum', 'Zeit'], axis=1, inplace = True)
print(data)
print(data.dtypes)

das gibt nun:

Code: Alles auswählen

   Art  Menge    Preis               DatumZeit
0    B      1  11414.0 2018-11-15 12:21:48.423
1    B      1  11411.5 2018-11-15 12:21:28.278
2    B      1  11410.5 2018-11-15 12:21:17.498
3    B      1  11411.0 2018-11-15 12:21:17.495

Code: Alles auswählen

[72 rows x 4 columns]
Art                  object
Menge                 int64
Preis               float64
DatumZeit    datetime64[ns]
dtype: object
Ich habe nun also tatsächlich eine Spalte 'DatumZeit', welche die String- Spalten 'Datum' und 'Zeit' ersetzt mit einer datetime Spalte, mit der man jetzt auch rechen kann.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum ignorierst Du die Antworten von ThomasL und mir, die Dir zeigen, dass alles, was Du hier so kompliziert in vielen Zeilen erledigst auch im Aufruf von read_clipboard gemacht werden kann?
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Sirius3 hat geschrieben: Samstag 1. Dezember 2018, 22:13 Das ist das Problem, wenn man kaputte Datenformate hat, mit denen man arbeiten muß. Zum Glück bietet Pandas tausend Optionen, wie man Daten lesen kann.

Code: Alles auswählen

data = pandas.read_clipboard(delimiter='\t',
    header=None, index_col=['Datum', 'Zeit', 'B/S', 'Menge', 'Preis'],
    parse_dates=[['Datum', 'Zeit']], date_parser=lambda d:dateutil.parser.parse('.'.join(d.rsplit(':',1))))
Hallo Sirius,
fand deine Lösung sehr elegant und wollte sie als Snippet ablegen, aber dein date_parser funzt so bei mir nicht.
Habe einiges ausprobiert und bin jetzt bei diesem Code gelandet, kann man das noch optimieren?

Code: Alles auswählen

dateparse = lambda d: dateutil.parser.parse(d.replace(':','.').replace('.',':',2))
df = pd.read_clipboard(delimiter='\t', header=None, names=['Datum', 'Zeit', 'B/S', 'Menge', 'Preis'],
                      parse_dates=[['Datum', 'Zeit']], date_parser=dateparse)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
SautaRoc
User
Beiträge: 48
Registriert: Donnerstag 20. September 2018, 13:18

@Sirius und ThomasL, ich ignoriere eure Antworten keineswegs. Sie sind wohl nur eingetroffen während ich an meinem letzten Post sass. Dadurch hat sich das überschnitten. Vielen Dank für die Hinweise. Das Problem für einen Anfänger wie mich ist halt, dass man den Wald vor lauter Bäumen nicht sieht. Ich versuche immer erst alles alleine, nur wenn es stundenlang nicht weitergeht frage ich nach. Daher sind meine Erstlösungen sicher nicht elegant, aber oft sind es Lösungen. Trotzdem bin ich sehr dankbar, wenn mir dann jemand zeigt wie man es mit zwei Zeilen elegant lösen kann - Dann verstehe ich es wenigstens....
SautaRoc
User
Beiträge: 48
Registriert: Donnerstag 20. September 2018, 13:18

Noch eine kleine Ergänzug, die mir gerade aufgefallen ist:

beim einlesen der Daten aus dem Clipboard muss noch header = None ergänzt werden, sonst wird beim setzen der Spaltenüberschriften die erste Datenzeile überschrieben.

Code: Alles auswählen

data = pd.read_clipboard(delimiter='\t', header = None)
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

SautaRoc hat geschrieben: Samstag 1. Dezember 2018, 22:33 also,

die strftime Referenz sagt

Code: Alles auswählen

%I    Hour (12-hour clock) as a zero-padded decimal number.    07
(http://strftime.org/). Das sollte also passen
Nein das sollte nicht passen, jedenfalls nicht wenn Du jede beliebige Zeit am Tag in den Daten haben kannst. Denn ein Tag hat nicht 12 sondern 24 Stunden. Wenn man also das 12 Stunden-Format nimmt, muss man ja noch irgendwo die Information her bekommen ob die Zeitangabe vor oder nach Mittags ist. Und da die Information nirgends in Deinen Daten zu stehen scheint, hast Du entweder dort schon ein Problem, oder Du hast grundsätzlich nur Zeiten von Mitternacht bis Mittags, oder das funktioniert so nicht.

Falls die Information vor oder nach Mittags doch in den Daten steht, dann müsstest Du die noch zusätzlich verarbeiten. Davon ist aber weder in Deiner Zeichenkette für das Zeitformat noch im Code etwas zu sehen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten