【问题标题】:Python - fastest way to populate a dataframe with a condition based on an index in another dataframePython - 使用基于另一个数据帧中的索引的条件填充数据帧的最快方法
【发布时间】:2019-07-31 23:51:14
【问题描述】:

我在输入数据帧 (input_df) 中有数据。基于另一个基准数据帧(bm_df)中的索引,我想创建第三个数据帧(output_df),该数据帧是根据使用原始两个数据帧中的索引的条件填充的。

对于 bm_df 索引中的每个日期,我想使用 input_df 中可用的最新数据填充我的输出,条件是数据的索引日期早于或等于 bm_df 中的索引日期。例如,在案例研究中,第一个索引日期 (2019-01-21) 的输出数据框下方的数据将使用来自 2019-01-21 的 input_df 数据点的数据进行填充。但是,如果 2019-01-21 的数据点不存在,则将使用 2019-01-18。

此处的用例是映射和回填大型数据集以获取给定日期的最新可用数据。我已经编写了一些 python 来为我做这件事(这很有效),但是我认为可能有一种更 Pythonic 并且因此更快的方法来实现该解决方案。我应用的基础数据集在列数和列长度方面具有很大的维度,因此我想要尽可能高效的东西 - 我当前的解决方案在我正在使用的完整数据集上运行时太慢了。

非常感谢任何帮助!

输入_df:

index   data
2019-01-21  0.008
2019-01-18  0.016
2019-01-17  0.006
2019-01-16  0.01
2019-01-15  0.013
2019-01-14  0.017
2019-01-11  0.017
2019-01-10  0.024
2019-01-09  0.032
2019-01-08  0.012

bm_df:

index   
2019-01-21  
2019-01-14  
2019-01-07  

输出_df:

index   data
2019-01-21  0.008
2019-01-14  0.017
2019-01-07  NaN

请看下面我目前使用的代码:

import pandas as pd
import numpy as np

# Import datasets
test_index = ['2019-01-21','2019-01-18','2019-01-17','2019-01-16','2019-01-15','2019-01-14','2019-01-11','2019-01-10','2019-01-09','2019-01-08']    
test_data = [0.008, 0.016,0.006,0.01,0.013,0.017,0.017,0.024,0.032,0.012]
input_df= pd.DataFrame(test_data,columns=['data'], index=test_index)

test_index_2= ['2019-01-21','2019-01-14','2019-01-07']  
bm_df= pd.DataFrame(index=test_index_2)

#Preallocate
data_mat= np.zeros([len(bm_df)])

#Loop over bm_df index and find the most recent variable from input_df which from a date before the index date 
for i in range(len(bm_df)):
    #First check to see if there are no dates before the selected date, if true fill with NaN
    if sum(input_df.index <= bm_df.index[i])>0:
        data_mat[i] = input_df['data'][max(input_df.index[input_df.index <= bm_df.index[i]])]
    else:
        data_mat[i] = float('NaN')

output_df= pd.DataFrame(data_mat,columns=['data'],index=bm_df.index)

【问题讨论】:

    标签: python loops dataframe indexing


    【解决方案1】:

    我没有测试执行时间,但我会依赖 join 在 pandas documentation 中被引用为高效

    ...一次通过索引有效地连接多个 DataFrame 对象...

    我会使用 shift 来获取搜索日期之前的最高日期的值。

    所有给予:

    output_df = bm_df.join(input_df.shift(-1), how='left')
    
                 data
    2019-01-21  0.016
    2019-01-14  0.017
    2019-01-07    NaN
    

    这种方法确实远不如显式循环通用。这是熊猫矢量化的代价。例如,对于 小于或等于 条件,代码会略有不同。这是一个示例,其中bm_df 中的附加日期在input_df 中不存在:

    ...
    test_index_2= ['2019-01-21','2019-01-14','2019-01-13','2019-01-07']  
    ...
    tmp_df = input_df.join(bm_df).fillna(method='bfill')
    output_df = bm_df.join(tmp_df, how='inner')
    

    我们得到了预期:

                 data
    2019-01-21  0.008
    2019-01-14  0.017
    2019-01-13  0.017
    2019-01-07  0.012
    

    【讨论】:

    • 我不确定这就是我想要的。使用连接不允许我明确指定条件。我怎么能在这个框架中设置等于或小于???此外(我认为)以这种方式连接需要日期出现在输入数据帧(然后移位相对于)和 bm 数据帧的索引中。可能存在并非如此的情况。
    • 我已经稍微修改了问题以使其更清楚。
    • @MCYeates:pandas 对于矢量化操作来说要快得多。如果您想快速,您应该努力找到满足您要求的矢量化方式,即使它看起来不那么明显。外连接和fillna(method='bfill') 将给出小于或等于的预期值。看看我的编辑。
    • join 和 fillna(method='bfill') 的组合对我有用。感谢您的帮助并注意到矢量化操作。
    猜你喜欢
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 2018-07-15
    • 2018-10-03
    • 2021-12-25
    • 1970-01-01
    • 2020-09-18
    • 1970-01-01
    相关资源
    最近更新 更多