pd.Timedelta is a great addition, thanks!
Is it the intended behavior of pd.Timedelta to only accept np.int64, python ints, and python floats? I ran into this when I tried to construct a list of pd.Timedeltas from the np.int32 array returned by pd.DatetimeIndex.dayofyear.
>>> import pandas as pd
>>> import numpy as np
>>> pd.Timedelta(days=np.int64(1))
Timedelta('1 days 00:00:00')
>>> pd.Timedelta(days=np.int32(1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pandas/tslib.pyx", line 1638, in pandas.tslib.Timedelta.__new__ (pandas/tslib.c:27693)
ValueError: cannot construct a TimeDelta from the passed arguments, allowed keywords are [days, seconds, microseconds, milliseconds, minutes, hours, weeks]
>>> pd.Timedelta(days=np.int16(1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pandas/tslib.pyx", line 1638, in pandas.tslib.Timedelta.__new__ (pandas/tslib.c:27693)
ValueError: cannot construct a TimeDelta from the passed arguments, allowed keywords are [days, seconds, microseconds, milliseconds, minutes, hours, weeks]
>>> pd.Timedelta(days=np.float64(1))
Timedelta('1 days 00:00:00')
>>> pd.Timedelta(days=np.float32(1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pandas/tslib.pyx", line 1638, in pandas.tslib.Timedelta.__new__ (pandas/tslib.c:27693)
ValueError: cannot construct a TimeDelta from the passed arguments, allowed keywords are [days, seconds, microseconds, milliseconds, minutes, hours, weeks]
>>> pd.Timedelta(days=1)
Timedelta('1 days 00:00:00')
>>> pd.Timedelta(days=1.0)
Timedelta('1 days 00:00:00')
Here's my version info:
>>> pd.show_versions()
INSTALLED VERSIONS
------------------
commit: None
python: 2.7.6.final.0
python-bits: 64
OS: Linux
OS-release: 2.6.32-431.17.1.el6.x86_64
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
pandas: 0.15.1
nose: 1.3.4
Cython: 0.21
numpy: 1.9.1
scipy: 0.14.0
statsmodels: None
IPython: 2.3.0
sphinx: 1.2.3
patsy: None
dateutil: 2.2
pytz: 2014.9
bottleneck: None
tables: None
numexpr: None
matplotlib: 1.4.0
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
httplib2: None
apiclient: None
rpy2: None
sqlalchemy: 0.9.7
pymysql: 0.6.2.None
psycopg2: None
Comment From: jreback
hmm be a little too strict in this but sure easy enough to add
interested in doing a pull-request?
Comment From: jreback
out of curiosity did you manually download? this should not be visible yet in pypi (I am waiting to put all the binaries there before releasing it)
Comment From: wholmgren
pandas 0.15.1? I just did a pip install pandas --upgrade
this morning (I was on .14). I was a little surprised that it started downloading 0.15.1 but I didn't look into it.
I'll take a shot at the pull request.
Comment From: wholmgren
Further documentation... pd.Timedelta
cannot accept np.int64
on python 3.3 or 3.4, however np.float64
does work.
>>> import pandas as pd
>>> import numpy as np
>>> pd.Timedelta(days=np.int64(1))
Traceback (most recent call last):
File "pandas/tslib.pyx", line 1636, in pandas.tslib.Timedelta.__new__ (pandas/tslib.c:27653)
TypeError: unsupported type for timedelta days component: numpy.int64
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pandas/tslib.pyx", line 1638, in pandas.tslib.Timedelta.__new__ (pandas/tslib.c:27693)
ValueError: cannot construct a TimeDelta from the passed arguments, allowed keywords are [days, seconds, microseconds, milliseconds, minutes, hours, weeks]
>>> pd.Timedelta(days=1)
Timedelta('1 days 00:00:00')
>>> pd.Timedelta(days=np.float64(1))
Timedelta('1 days 00:00:00')
>>> pd.Timedelta(days=np.float32(1))
Traceback (most recent call last):
File "pandas/tslib.pyx", line 1636, in pandas.tslib.Timedelta.__new__ (pandas/tslib.c:27653)
TypeError: unsupported type for timedelta days component: numpy.float32
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pandas/tslib.pyx", line 1638, in pandas.tslib.Timedelta.__new__ (pandas/tslib.c:27693)
ValueError: cannot construct a TimeDelta from the passed arguments, allowed keywords are [days, seconds, microseconds, milliseconds, minutes, hours, weeks]
>>> pd.show_versions()
INSTALLED VERSIONS
------------------
commit: None
python: 3.4.2.final.0
python-bits: 64
OS: Linux
OS-release: 2.6.32-431.17.1.el6.x86_64
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
pandas: 0.15.1
nose: 1.3.4
Cython: None
numpy: 1.9.1
scipy: 0.14.0
statsmodels: None
IPython: 2.3.0
sphinx: None
patsy: None
dateutil: 2.2
pytz: 2014.9
bottleneck: None
tables: None
numexpr: None
matplotlib: 1.4.2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
httplib2: None
apiclient: None
rpy2: None
sqlalchemy: None
pymysql: None
psycopg2: None
Comment From: wholmgren
ack. sorry bout the close.
Comment From: jreback
floats are legit, mostly, eg.
pd.Timedelta('1.5d')
Timedelta('1 days 12:00:00')
not 100% sure about accepting this though:
pd.Timedelta(days=1.5)
prob need some validation
though pd.Timedelta(days=np.float32(1))
should work
e.g. if x == int(x)
(a whole integer) then for sure ok, even if its a float
Comment From: wholmgren
Now that I've looked at the source code, I see that it's failing when trying to construct a python datetime.timedelta
. So, I think that the blame lies with numpy for failing to provide python with the right translation.
In [13]: datetime.timedelta(days=1)
Out[13]: datetime.timedelta(1)
In [14]: datetime.timedelta(days=1.0)
Out[14]: datetime.timedelta(1)
In [15]: datetime.timedelta(days=np.int64(1.0))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-194c3cc228db> in <module>()
----> 1 datetime.timedelta(days=np.int64(1.0))
TypeError: unsupported type for timedelta days component: numpy.int64
In [16]: datetime.timedelta(days=np.float64(1.0))
Out[16]: datetime.timedelta(1)
In [17]: datetime.timedelta(days=np.float32(1.0))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-17-2055ee731de0> in <module>()
----> 1 datetime.timedelta(days=np.float32(1.0))
TypeError: unsupported type for timedelta days component: numpy.float32
In [19]: datetime.timedelta(dayss=1)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-19-699cc4692f32> in <module>()
----> 1 datetime.timedelta(dayss=1)
TypeError: 'dayss' is an invalid keyword argument for this function
I'm not sure if it's appropriate to provide a work around here or not. At the very least, I think that the exception text should be made more accurate. It's a little tricky because both exceptions are classified as TypeErrors. One possibility would be to simply remove the try/except on line 1635 and let the python message through. Another possibility would be to check the python exception text for 'is an invalid keyword' or similar, and if true, raise the current pandas error, and if false, raise the error verbatim.
Thoughts?
Comment From: jreback
see here: https://github.com/pydata/pandas/blob/master/pandas/tslib.pyx
i would just iterate on the kwargs and coerce the not-None values to ints here (side issue is what to do with a float that is not == to its int value).
Comment From: jpweytjens
pd.Timedelta
now supports np.int
, but it's close cousin pd.Dateoffset
does not when using pandas version 1.5.3 and numpy version 1.23.5.
import pandas as pd
import numpy as np
date = pd.Timestamp(year=2000, month=1, day=1)
dtypes = [int, float, np.int64, np.int32, np.float64, np.float32]
for dtype in dtypes:
try:
date + pd.DateOffset(days=dtype(1))
except:
print(f"{dtype} is not supported with pd.DateOffset.")
try:
date + pd.Timedelta(value=dtype(1), unit="days")
except:
print(f"{dtype} is not supported with pd.TimeDelta.")
I'll open a PR, similar to #8787 when I can find the time.