You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
DataFrame(::PyPandasDataFrame) converts date & datetime to bytes #293
When doing some work involving dataframes in python via PythonCall, it seems like DataFrame(PyTable(p)) where p is a pandas data table converts the date and datetime columns into byte vectors. Is this issue related to the issue #265 with milliseconds vs microseconds, or due to a missing part of the DataFrame(::PyPandasDataFrame) implementation?
Here are a few minimal examples, in a conda environment with pandas.
using PythonCall
using Dates
using DataFrames
a = DataFrame(x = [now()]) # julia dataframe
b = pytable(a) # pandas dataframe
c = PyTable(b) # PyPandasDataFrame
d = DataFrame(c) # julia dataframe again
This results in:
julia> c
1×1 PyPandasDataFrame
x
0 2023-04-13 14:36:13.939
julia> d
1×1 DataFrame
Row │ x
│ PyArray…
─────┼───────────────────────────────────
1 │ UInt8[0xc0, 0x62, 0x31, 0x8c, 0x…
The same thing happens when initially defining b as a pandas dataframe, so the microsecond issue in #265 seems to not be the problem?
changed the title [-]`DataFrame(::PyPandasDataFrame) ` converts datetime to bytes[/-][+]`DataFrame(::PyPandasDataFrame)` converts datetime to bytes[/+]on Apr 13, 2023
changed the title [-]`DataFrame(::PyPandasDataFrame)` converts datetime to bytes[/-][+]`DataFrame(::PyPandasDataFrame)` converts date & datetime to bytes[/+]on Apr 13, 2023
If you replace the now() with today() in the specific example I gave, it converts dates correctly, but in my use case where I had two date columns and two datetime columns, both the date and datetime columns are converted to byte vectors
Just looking at this now. It all comes down to the fact that numpy arrays containing numpy.datetime64 cannot be wrapped as a Julia array yet. Therefore it's falling back on converting each element, and because numpy.datetime64 actually implements the buffer protocol with itemtype=1byte, that gets converted to a PyArray{UInt8} as you're seeing.
So there's two things that could be fixed here:
Support wrapping arrays containing datetime64
Support converting datetime64 to something more useful than PyArray{UInt8}.
@cjdoris
If I eliminate .values in line 61 of PyPandasDataFrame everything runs smoothly. Would that be an option or is there some performance issue or other issue that I am not aware of?
UPDATE: That doesn't work, columns will be vectors of Py objects
If you replace the now() with today() in the specific example I gave, it converts dates correctly, but in my use case where I had two date columns and two datetime columns, both the date and datetime columns are converted to byte vectors
@tomdstone
Could you check if also your use case where you had difficulties with time is working with the PR in place?
Otherwise, please share an MWE.
I could try to cover your use case as well.
@hhaensel sorry, I won't have time to implement it due to how work is right now (we are in the middle of a move). I might follow up in a few months, but I definitely wouldn't hold your breath waiting for me. I appreciate the thought though!
@cjdoris
I added automatic conversion from Periods/CompoundPeriods to numpy:timedelta64 as this supports nanoseconds as well. When I use pytimedeltatype, I can only go down to microseconds. Is that a good decision? It seems that pandas can convert the timedelta64 to a timestamp.timedelta that handles nanoseconds correctly.
For conversion from timedelta to Julia I used Dates.CompoundPeriod in order to be type stable. Otherwise one could use Nanosecond, but that seemed a bit weired to me.
I know you're working for version 1 to come out soon. I hope my proposal fits in there somehow.
julia> x =Py(Second(1))
Python: numpy.timedelta64(1,'s')
julia>pyconvert(Second, x)
1 second
julia> x =Py(Second(1) +Nanosecond(1))
Python: numpy.timedelta64(1000000001,'ns')
julia> y =pyconvert(Any, x)
1 second, 1 nanosecond
julia>typeof(y)
Dates.CompoundPeriod
julia> jdf =DataFrame(x = [now() +Second(rand(1:1000)) for _ in1:100], y = [Second(n) for n in1:100]);
julia> pdf =pytable(jdf)
Python:
x y
02023-07-0411:29:27.7810 days 00:00:0112023-07-0411:30:02.7810 days 00:00:0222023-07-0411:40:17.7810 days 00:00:0332023-07-0411:31:11.7810 days 00:00:04...5 more lines ...982023-07-0411:37:21.7810 days 00:01:39992023-07-0411:35:53.7810 days 00:01:40
[100 rows x 2 columns]
julia> jdf2 =DataFrame(PyTable(pdf))
100×2 DataFrame
Row │ x y
│ DateTime Compound…
─────┼──────────────────────────────────────
1 │ 2023-07-04T11:29:27.7811 second
2 │ 2023-07-04T11:30:02.7812 seconds
3 │ 2023-07-04T11:40:17.7813 seconds
⋮ │ ⋮⋮99 │ 2023-07-04T11:37:21.78199 seconds
100 │ 2023-07-04T11:35:53.781100 seconds
95 rows omitted
This issue has been marked as stale because it has been open for 30 days with no activity. If the issue is still relevant then please leave a comment, or else it will be closed in 7 days.
I'd be ready to adapt the my PR to the latest changes of PythonCall. Should I continue to work on it? Is the refactoring complete or should I still wait a bit?
Activity
[-]`DataFrame(::PyPandasDataFrame) ` converts datetime to bytes[/-][+]`DataFrame(::PyPandasDataFrame)` converts datetime to bytes[/+][-]`DataFrame(::PyPandasDataFrame)` converts datetime to bytes[/-][+]`DataFrame(::PyPandasDataFrame)` converts date & datetime to bytes[/+]tomdstone commentedon Apr 13, 2023
If you replace the
now()withtoday()in the specific example I gave, it converts dates correctly, but in my use case where I had two date columns and two datetime columns, both the date and datetime columns are converted to byte vectorscjdoris commentedon Apr 24, 2023
Just looking at this now. It all comes down to the fact that numpy arrays containing
numpy.datetime64cannot be wrapped as a Julia array yet. Therefore it's falling back on converting each element, and becausenumpy.datetime64actually implements the buffer protocol with itemtype=1byte, that gets converted to aPyArray{UInt8}as you're seeing.So there's two things that could be fixed here:
datetime64datetime64to something more useful thanPyArray{UInt8}.cjdoris commentedon Apr 24, 2023
(PS thanks for the report and the MWE)
hhaensel commentedon Jun 29, 2023
Just stumbled across that problem and solved it this way:
EDIT: This only holds for datetime64[ns], otherwise the factor is different. I just filed a tentative PR for a general solution
hhaensel commentedon Jun 30, 2023
@cjdoris
If I eliminate
.valuesin line 61 of PyPandasDataFrame everything runs smoothly. Would that be an option or is there some performance issue or other issue that I am not aware of?UPDATE: That doesn't work, columns will be vectors of Py objects
hhaensel commentedon Jul 1, 2023
@tomdstone
Could you check if also your use case where you had difficulties with time is working with the PR in place?
Otherwise, please share an MWE.
I could try to cover your use case as well.
hhaensel commentedon Jul 2, 2023
Just added support for timedelta and timedelta64 conversion to Dates.CompoundPeriod.
tomdstone commentedon Jul 3, 2023
@hhaensel sorry, I won't have time to implement it due to how work is right now (we are in the middle of a move). I might follow up in a few months, but I definitely wouldn't hold your breath waiting for me. I appreciate the thought though!
hhaensel commentedon Jul 3, 2023
Thanks for the reply. No need to hurry. I just filed the PR as I was in need of a solution for my use case.
hhaensel commentedon Jul 4, 2023
@cjdoris
I added automatic conversion from Periods/CompoundPeriods to numpy:timedelta64 as this supports nanoseconds as well. When I use pytimedeltatype, I can only go down to microseconds. Is that a good decision? It seems that pandas can convert the timedelta64 to a timestamp.timedelta that handles nanoseconds correctly.
For conversion from timedelta to Julia I used Dates.CompoundPeriod in order to be type stable. Otherwise one could use Nanosecond, but that seemed a bit weired to me.
I know you're working for version 1 to come out soon. I hope my proposal fits in there somehow.
hhaensel commentedon Jul 4, 2023
Just want to share what's working now with the PR
github-actions commentedon Aug 22, 2023
This issue has been marked as stale because it has been open for 30 days with no activity. If the issue is still relevant then please leave a comment, or else it will be closed in 7 days.
hhaensel commentedon Aug 22, 2023
@cjdoris I think this is still relevant
klwlevy commentedon Aug 28, 2023
I agree. Just stumbled on this when using pandas functionality to convert (legacy) xls data to xlsx. The dates became PyArray{UInt8}.
hhaensel commentedon Jun 10, 2024
I'd be ready to adapt the my PR to the latest changes of PythonCall. Should I continue to work on it? Is the refactoring complete or should I still wait a bit?
cjdoris commentedon Jun 13, 2024
Yep the refactor is done. Can you clarify what the PR will change?
hhaensel commentedon Jun 14, 2024
I think I summarised everything quite nicely above (#293 (comment))
The related PR is #334, where you commented that you are refactoring.
hhaensel commentedon Jun 17, 2024
@cjdoris After refactoring I decided that it is easier to submit a new PR #509