【问题标题】:pyjanitor conditional joins between date range based on columnspyjanitor 基于列的日期范围之间的条件连接
【发布时间】:2022-09-26 11:26:00
【问题描述】:

数据Merging Pandas DataFrame within a specific Date Range

我想使用 pyjanitor 来引用这个 post 但如果同时与其他列合并,它不会给出。

尝试

df_1.conditional_join(
...     df_2,
...     (\"InvoiceDate \", \"PromotionStart \", \">=\"),
...     (\"InvoiceDate \", \"PromotionEnd \", \"<=\")
... )

输出

+------------+-------------+---------------+-----------+
| LocationNo | InvoiceDate | InvoiceAmount | Promotion |
+------------+-------------+---------------+-----------+
|      A     |  01-Jul-20  |       79      |    Yes    |
+------------+-------------+---------------+-----------+
|      B     |  01-Jul-20  |       72      |           |
+------------+-------------+---------------+-----------+
|      C     |  01-Jul-20  |       24      |           |
+------------+-------------+---------------+-----------+
|      A     |  02-Jul-20  |       68      |    Yes    |
+------------+-------------+---------------+-----------+
|      B     |  02-Jul-20  |       6       |    Yes    |
+------------+-------------+---------------+-----------+
|      C     |  02-Jul-20  |       27      |           |
+------------+-------------+---------------+-----------+
|      A     |  03-Jul-20  |       25      |           |
+------------+-------------+---------------+-----------+
|      B     |  03-Jul-20  |       62      |    Yes    |
+------------+-------------+---------------+-----------+
|      C     |  03-Jul-20  |       58      |    Yes    |
+------------+-------------+---------------+-----------+
|      D     |  03-Jul-20  |       36      |    Yes    |
+------------+-------------+---------------+-----------+
|      E     |  03-Jul-20  |       65      |           |
+------------+-------------+---------------+-----------+
|      F     |  03-Jul-20  |       81      |           |
+------------+-------------+---------------+-----------+
  • 你想得到什么输出?
  • @HenryEcker 我更新了。
  • 思考您正在寻找类似df_1.conditional_join(df_2, (\'LocationNo\', \'LocationNo\', \'==\'), (\'InvoiceDate\', \'PromotionStart\', \'&gt;=\'), (\'InvoiceDate\', \'PromotionEnd\', \'&lt;=\'), how=\'left\') 的东西,但我不确定为什么您会在此处使用conditional_join 而不是标准合并后跟where(如链接帖子中的the answer)。

标签: pandas pyjanitor


【解决方案1】:

使用conditional_join,您需要包含另一个用于 equi 连接的元组:

import pandas as pd
import janitor

df_1['InvoiceDate'] = pd.to_datetime(df_1['InvoiceDate'])
df_2['PromotionStart'] = pd.to_datetime(df_2['PromotionStart'])
df_2['PromotionEnd'] = pd.to_datetime(df_2['PromotionEnd'])

(df_1
.conditional_join(
    df_2, 
    ('LocationNo', 'LocationNo', '=='), 
    ('InvoiceDate', 'PromotionStart', '>='), 
    ('InvoiceDate', 'PromotionEnd', '<='))
)
        left                                right
  LocationNo InvoiceDate InvoiceAmount LocationNo PromotionStart PromotionEnd
0          A  2020-07-01            79          A     2020-07-01   2020-07-02
1          A  2020-07-02            68          A     2020-07-01   2020-07-02
2          B  2020-07-02             6          B     2020-07-02   2020-07-03
3          B  2020-07-03            62          B     2020-07-02   2020-07-03
4          C  2020-07-03            58          C     2020-07-03   2020-07-05
5          D  2020-07-03            36          D     2020-07-01   2020-07-05

正如@HenryEcker 正确指出的那样,您的问题可以通过合并然后过滤来解决。对于您的用例,conditional_join 可能有点矫枉过正;但是,根据数据大小,对于 equi 连接,conditional_join 所做的是拦截从 pandas internal merge function(哈希实现)生成的索引,然后在创建最终数据帧之前运行非 equi 连接.与严格的非 equi 连接不同,不进行排序,因为 equi 连接的哈希合并通常更快(警告 - R 的 data.table 对其连接使用某种形式的二进制搜索并且速度非常快,通常甚至比 Pandas 更快)。对于大型数据帧,它可能会带来一些性能提升;您的里程可能会有所不同。

让我们看一个包含一百万行的愚蠢示例——下面的代码基于dev version

# pip install git+https://github.com/pyjanitor-devs/pyjanitor.git

np.random.seed(3)
df = pd.DataFrame({'start':np.random.randint(100_000, size=1_000_000),
                   'end':np.random.randint(100_000, size=1_000_000)})
dd = pd.DataFrame({'ID':np.random.randint(100_000, size=1_500_000)})

df.head()
   start    end
0  71530  85703
1  67224  37802
2  77049    652
3  59011  99059
4  48056  26108

dd.head()
      ID
0  25816
1  92958
2  62607
3  89684
4  13434


%timeit df.merge(dd, left_on='start', right_on = 'ID').loc[lambda df: df.end >= df.ID]
1.27 s ± 17.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df.conditional_join(dd, ('start', 'ID', '=='), ('end', 'ID', '>='))
597 ms ± 16.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


# verify both dataframes are the same
cond_join = df.conditional_join(dd, ('start', 'ID', '=='), ('end', 'ID', '>='))

pd_merge = df.merge(dd, left_on='start', right_on = 'ID').loc[lambda df: df.end >= df.ID]

pd_merge.reset_index(drop=True).equals(cond_join)
True


# memory consumption
In [167]: %load_ext memory_profiler

In [168]: %memit df.conditional_join(dd, ('start', 'ID', '=='), ('end', 'ID', '>='))
peak memory: 1599.06 MiB, increment: 173.16 MiB

In [169]: %memit df.merge(dd, left_on='start', right_on = 'ID').loc[lambda df: df.end >= df.ID]
peak memory: 2207.29 MiB, increment: 624.08 MiB

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2020-02-20
    相关资源
    最近更新 更多