Ich schreibe eine Funktion, um Werte aus Datumsangaben über Arrays zu extrahieren. Ich möchte, dass die Funktion auf einem Pandas DataFrame oder einem numpy ndarray arbeitet.Python/Numpy: Probleme mit der Typkonvertierung in Vektorisieren und Element
Die Werte sollten auf die gleiche Weise zurückgegeben werden wie die Python-Datetime-Eigenschaften, z.
from datetime import datetime
dt = datetime(2016, 10, 12, 13)
dt.year
=> 2016
dt.second
=> 0
Für einen Datenrahmen ist dies relativ einfach zu handhaben mit applymap()
(obwohl es auch einen besseren Weg sein kann). Ich habe den gleichen Ansatz für numpy ndarrays mit vectorize()
versucht, und ich stoße auf Probleme. Statt der Werte, die ich erwartet hatte, habe ich sehr große Zahlen, manchmal negative.
Das war ziemlich zunächst rätselhaft, aber ich herausgefunden, was passiert ist: wird mit item
statt __get__
bekommen die vektorisiert Funktion die Werte aus dem ndarray. Dies scheint automatisch jedes datetime64
Objekt in ein long
zu konvertieren:
nd[1][0]
=> numpy.datetime64('1986-01-15T12:00:00.000000000')
nd[1].item()
=> 506174400000000000L
Die lange scheint die Zahl der ns seit Epoche zu sein (1970-01-01T00: 00: 00). Irgendwo entlang der Linie werden die Werte in ganze Zahlen umgewandelt und sie überlaufen, daher die negativen Zahlen.
Das ist also das Problem. Kann mir bitte jemand helfen, es zu reparieren? Das einzige, was ich mir vorstellen kann, ist die manuelle Konvertierung, aber das würde bedeuten, einen Teil des datetime
Moduls neu zu implementieren.
Gibt es eine Alternative zu vectorize
, die item()
nicht verwendet?
Danke!
Minimal Codebeispiel:
## DataFrame works fine
import pandas as pd
from datetime import datetime
df = pd.DataFrame({'dts': [datetime(1970, 1, 1, 1), datetime(1986, 1, 15, 12),
datetime(2016, 7, 15, 23)]})
exp = pd.DataFrame({'dts': [1, 15, 15]})
df_func = lambda x: x.day
out = df.applymap(df_func)
assert out.equals(exp)
## numpy ndarray is more difficult
from numpy import datetime64 as dt64, timedelta64 as td64, vectorize # for brevity
# The unary function is a little more complex, especially for days and months where the minimum value is 1
nd_func = lambda x: int((dt64(x, 'D') - dt64(x, 'M') + td64(1, 'D'))/td64(1, 'D'))
nd = df.as_matrix()
exp = exp.as_matrix()
=> array([[ 1],
[15],
[15]])
# The function works as expected on a single element...
assert nd_func(nd[1][0]) == 15
# ...but not on an ndarray
nd_vect = vectorize(nd_func)
out = nd_vect(nd)
=> array([[ -105972749999999],
[ 3546551532709551616],
[-6338201187830896640]])
Dank @hpaulj, Sie machen einen ausgezeichneten Punkt, um dort für vectorize keine Notwendigkeit zu sein - benutze 'astype ('datetime64 [$ UNIT]')' (hoffentlich kannst du meine fürchterlich gemischte Syntax dort durchsehen) auf dem ganzen Array funktioniert ein Leckerbissen – charrison