<h2>目前还没有pandami这样做的方式</h2>
<p>这个答案过去是关于处理多态性的问题,结果发现这是一个非常糟糕的主意。</p>
<p>然后<a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.piecewise.html" rel="nofollow noreferrer">^{<cd1>}</a>函数出现在另一个答案中,但是没有什么解释,所以我想我会澄清如何使用这个函数。</p>
<h2>分段的Numpy方式(内存很重)</h2>
<p><a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.piecewise.html" rel="nofollow noreferrer">^{<cd2>}</a>函数可用于生成自定义联接的行为。这涉及到很多开销,而且效率不高,但它确实起到了作用。</p>
<h3>连接的生产条件</h3>
<pre><code>import pandas as pd
from datetime import datetime
presidents = pd.DataFrame({"name": ["Bush", "Obama", "Trump"],
"president_id":[43, 44, 45]})
terms = pd.DataFrame({'start_date': pd.date_range('2001-01-20', periods=5, freq='48M'),
'end_date': pd.date_range('2005-01-21', periods=5, freq='48M'),
'president_id': [43, 43, 44, 44, 45]})
war_declarations = pd.DataFrame({"date": [datetime(2001, 9, 14), datetime(2003, 3, 3)],
"name": ["War in Afghanistan", "Iraq War"]})
start_end_date_tuples = zip(terms.start_date.values, terms.end_date.values)
conditions = [(war_declarations.date.values >= start_date) &
(war_declarations.date.values <= end_date) for start_date, end_date in start_end_date_tuples]
> conditions
[array([ True, True], dtype=bool),
array([False, False], dtype=bool),
array([False, False], dtype=bool),
array([False, False], dtype=bool),
array([False, False], dtype=bool)]
</code></pre>
<p>这是一个数组列表,其中每个数组告诉我们,对于我们拥有的两个战争声明中的每一个,时间跨度这个词是否匹配。<strong>条件会随着更大的数据集而爆炸</strong>,因为它将是左df和右df的长度相乘。</p>
<h3>分段“魔术”</h3>
<p>现在分段将从术语中取出<code>president_id</code>,并将其放入每个对应的war的<code>war_declarations</code>数据帧中。</p>
<pre><code>war_declarations['president_id'] = np.piecewise(np.zeros(len(war_declarations)),
conditions,
terms.president_id.values)
date name president_id
0 2001-09-14 War in Afghanistan 43.0
1 2003-03-03 Iraq War 43.0
</code></pre>
<p>现在要完成这个例子,我们只需要定期合并总统的名字。</p>
<pre><code>war_declarations.merge(presidents, on="president_id", suffixes=["_war", "_president"])
date name_war president_id name_president
0 2001-09-14 War in Afghanistan 43.0 Bush
1 2003-03-03 Iraq War 43.0 Bush
</code></pre>
<h2>多态性(不起作用)</h2>
<p>我想和大家分享我的研究成果,所以即使这不能解决问题,我也希望至少能把它作为一个有用的回答留在这里。由于很难发现错误,其他人可能会尝试这样做,并认为他们有一个可行的解决方案,而事实上,他们没有</p>
<p>我唯一能想到的另一个方法是创建两个新类,一个PointInTime和一个Timespan</p>
<p>两者都应该有<code>__eq__</code>方法,如果将PointInTime与包含它的Timespan进行比较,则返回true。</p>
<p>之后,您可以用这些对象填充数据框,并连接它们所在的列。</p>
<p>像这样的:</p>
<pre><code>class PointInTime(object):
def __init__(self, year, month, day):
self.dt = datetime(year, month, day)
def __eq__(self, other):
return other.start_date < self.dt < other.end_date
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
return "{}-{}-{}".format(self.dt.year, self.dt.month, self.dt.day)
class Timespan(object):
def __init__(self, start_date, end_date):
self.start_date = start_date
self.end_date = end_date
def __eq__(self, other):
return self.start_date < other.dt < self.end_date
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
return "{}-{}-{} -> {}-{}-{}".format(self.start_date.year, self.start_date.month, self.start_date.day,
self.end_date.year, self.end_date.month, self.end_date.day)
</code></pre>
<p>重要提示:我没有对datetime进行子类划分,因为pandas会将datetime对象列的dtype视为datetime dtype,并且由于timespan不是,pandas会自动拒绝在它们上合并。</p>
<p>如果我们实例化这些类的两个对象,现在可以比较它们:</p>
<pre><code>pit = PointInTime(2015,1,1)
ts = Timespan(datetime(2014,1,1), datetime(2015,2,2))
pit == ts
True
</code></pre>
<p>我们还可以用这些对象填充两个数据帧:</p>
<pre><code>df = pd.DataFrame({"pit":[PointInTime(2015,1,1), PointInTime(2015,2,2), PointInTime(2015,3,3)]})
df2 = pd.DataFrame({"ts":[Timespan(datetime(2015,2,1), datetime(2015,2,5)), Timespan(datetime(2015,2,1), datetime(2015,4,1))]})
</code></pre>
<p>然后是融合的作品:</p>
<pre><code>pd.merge(left=df, left_on='pit', right=df2, right_on='ts')
pit ts
0 2015-2-2 2015-2-1 -> 2015-2-5
1 2015-2-2 2015-2-1 -> 2015-4-1
</code></pre>
<p>但只有一种。</p>
<p><code>PointInTime(2015,3,3)</code>也应该包含在<code>Timespan(datetime(2015,2,1), datetime(2015,4,1))</code>上的此联接中</p>
<p>但事实并非如此。</p>
<p>我想熊猫比较了<code>PointInTime(2015,3,3)</code>和<code>PointInTime(2015,2,2)</code>,并假设由于它们不相等,<code>PointInTime(2015,3,3)</code>不能等于<code>Timespan(datetime(2015,2,1), datetime(2015,4,1))</code>,因为这个时间跨度等于<code>PointInTime(2015,2,2)</code></p>
<p>有点像这样:</p>
<pre><code>Rose == Flower
Lilly != Rose
</code></pre>
<p>因此:</p>
<pre><code>Lilly != Flower
</code></pre>
<p>编辑:</p>
<p>我试图使所有的点彼此相等,这改变了连接的行为,将2015-3-3包括在内,但2015-2-2只包括在2015-2-1->;2015-2-5时间段内,所以这加强了我的上述假设。</p>
<p>如果有人有任何其他想法,请评论,我可以试试。</p>