我正在编写一个Pandas例程库,该库需要能够处理可能具有不同类型的数据帧中的日期。具体来说,我得到了datetime.date
和熊猫类型的不同组合。_libs. tslb.Timestamp
相当多。据报道(并通过我的测试证实),这与设置了多索引然后重置的帧有关。(请参阅我之前的问题什么改变了这个熊猫代码中的日期类型?,它解决了从多索引来回移动时类型被更改的问题。)
这里有一个简短(但做作)的例子:
import pandas as pd
df = pd.DataFrame(
data={
'date' : ['2019-01-01', '2019-01-02', '2019-01-03'],
'value' : [1, 2, 3],
'other' : [11, 12, 13]
}
)
df.date = pd.to_datetime(df.date).dt.date
print df.head()
date other value
0 2019-01-01 11 1
1 2019-01-02 12 2
2 2019-01-03 13 3
df_reindex = df.set_index(['date','other']).reset_index()
date other value
0 2019-01-01 11 1
1 2019-01-02 12 2
2 2019-01-03 13 3
print pd.merge(df, df_reindex, on='date')
Empty DataFrame
Columns: [date, other_x, value_x, other_y, value_y]
Index: []
print pd.merge(df, df, on='date')
date other_x value_x other_y value_y
0 2019-01-01 11 1 11 1
1 2019-01-02 12 2 12 2
2 2019-01-03 13 3 13 3
print pd.merge(df_reindex, df_reindex, on='date')
date other_x value_x other_y value_y
0 2019-01-01 11 1 11 1
1 2019-01-02 12 2 12 2
2 2019-01-03 13 3 13 3
print type(df.date[0])
<type 'datetime.date'>
print type(df_reindex.date[0])
<class 'pandas._libs.tslib.Timestamp'>
这里df
和df_reindex
本质上有相同的数据内容,但是,由于Pandas内部的类型在set_index
的位置已经改变,它们之间的合并是空的,而两者之间的“自合并”本身给出了预期的(尽管在这里的人为情况下,是多余和琐碎的)结果。
当然,真实的情况下,没有像这样随意地设置和重置索引就达到了这一点——真实的数据通过多个位代码,在不同的阶段执行不同的索引要求,合并是在具有一些不重叠列的帧之间进行的。
关于我关于使用NumPy datetime的另一个问题有一个评论,但这似乎是徒劳的,因为转换显然会导致两种有问题的数据类型之一,即底层Pandas类:
df_numpy = df.copy()
df_numpy.date = df.date.apply(np.datetime64)
print type(df.date[0])
<type 'datetime.date'>
print type(df_numpy.date[0])
<class 'pandas._libs.tslib.Timestamp'>
(更不用说我在现有框架内工作,因此此时可能无法强制所有帧都具有NumPy类型而不是Pandas类型。)
我需要做的是能够合并库代码中的表,无论它们是否被我控制之外的调用者如此操纵。我作为输入获得的数据帧不能更改。我可以复制它们并在副本上实现直接转换(就像这里熊猫在日期列问题上合并一样),但是帧有时很大,除非没有其他选择,否则我不想复制它们。
有没有办法让合并将这些识别为等价的?如果没有,是否有最佳实践选择日期格式来避免这里暴露的转换问题?
有没有办法让合并将这些识别为等价的?
不,不是当前的熊猫代码:
# datetimelikes must match exactly
elif is_datetimelike(lk) and not is_datetimelike(rk):
raise ValueError(msg)
elif not is_datetimelike(lk) and is_datetimelike(rk):
raise ValueError(msg)
elif is_datetime64tz_dtype(lk) and not is_datetime64tz_dtype(rk):
raise ValueError(msg)
elif not is_datetime64tz_dtype(lk) and is_datetime64tz_dtype(rk):
raise ValueError(msg)
如果没有,是否有最佳实践选择日期格式来避免此处暴露的转换问题?
我从您的问题中了解到,数据帧及其数据类型超出了您的控制范围,并且无法更改,因此这个问题不会给我们带来任何结果。
def merge_on_date(left, right, on):
from pandas.core.dtypes.common import is_datetimelike
try:
return pd.merge(left, right, on=on)
except:
if is_datetimelike(right[on]):
return pd.merge(left, right.assign(**{on: eval('right[on].dt.date')}), on=on)
else:
return pd.merge(left.assign(**{on: eval('left[on].dt.date')}), right, on=on)
结果:
>>> merge_on_date(df, df_reindex, 'date')
date value_x other_x other_y value_y
0 2019-01-01 1 11 11 1
1 2019-01-02 2 12 12 2
2 2019-01-03 3 13 13 3
>>> merge_on_date(df_reindex, df, 'date')
date other_x value_x value_y other_y
0 2019-01-01 11 1 1 11
1 2019-01-02 12 2 2 12
2 2019-01-03 13 3 3 13
然而,这个很大的缺点是分配
在幕后制作了一个副本。
PS:我刚刚看到pd. merge(df,df_reindex,on='date')
在您的示例中产生了一个空数据帧。从版本0.22.0开始,这应该会引发ValueError
。你使用的是什么版本?