我正在编写一个Pandas例程的库,它需要能够处理可能是不同类型的数据帧中的日期。具体来说,我得到了相当多的datetime.date和pandas._libs.tslib.Timestamp类型的不同组合。据报道(并通过我的测试证实)这与具有多索引设置然后重置的帧有关。(请参阅我前面的问题What changes type of date in this pandas code?,它解决了在多索引之间来回切换时类型被更改的问题。)
这里有一个简短的(但人为的)例子:
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具有本质上相同的数据内容,但是,由于类型在set_index处已在Pandas内部更改,因此它们之间的合并是空的,而两者之间的“自合并”给出了预期的结果(尽管在这里,人为设计的情况下,是多余的和微不足道的)。
当然,实际情况下,不需要像这样随意地设置和重置索引就可以达到这一点-实际数据通过多位代码,在不同阶段执行不同的索引要求,并且合并是在具有一些不重叠列的帧之间进行的。
我的另一个问题是使用NumPy datetimes,但这似乎是徒劳的,因为转换显然会导致两种有问题的数据类型之一,即底层的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类型。)
我需要做的是能够合并库代码中的表,无论它们是否被我控制之外的调用者如此操作。我获得的作为输入的数据帧不能更改。我可以复制它们并在副本上实现直接转换(就像这里的pandas merge on date column issue),但是帧有时很大,除非没有其他选择,否则我不想复制它们。
有没有办法让合并程序将它们识别为等价的?如果没有,有没有避免这里暴露的转换问题的日期格式的最佳实践选择?
发布于 2019-10-08 23:12:42
有没有办法让merge将它们识别为等价的?
不,不能使用当前的pandas code
# 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)如果没有,有没有避免这里暴露的转换问题的日期格式的最佳实践选择?
我从你的问题中了解到,数据帧和它们的数据类型不在你的控制范围之内,而且它们不能改变,所以这个问题不会给我们带来任何帮助。
您需要的是像SQL中那样的条件连接。有一个旧的开放issue用于这个功能,自2014年以来没有任何活动。(邀请PRs...)
一种可能的解决方法可能是这样的:
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然而,这一大缺点是引擎盖下的assign makes a copy。
PS:我刚刚在你的例子中看到了pd.merge(df, df_reindex, on='date')会产生一个空的数据帧。从版本0.22.0开始,这应该会引发ValueError。您使用的是什么版本?
https://stackoverflow.com/questions/58276892
复制相似问题