如何使用一个 np.where 语句更新数据框 A 的 3 列与数据框 B 的 3 列

How do I update 3 columns of dataframe A with 3 respective columns of dataframe B with one np.where statement

在下面的代码中,我创建了包含每日数据的 df_d 和一个包含每日数据的 df_i具有 5 分钟间隔的日内数据。

我想将 df_d 中的 3 列(Volume、Volume1 和 Volume2)传播到 df_i 各自的日期。

当我调用df_i, df_d = main_process()时,代码实现了结果。但是,当我运行它在大数据上时,这会占用很多时间。

如何仅用一个 np.where 语句更新 df_i 的 3 列?或者就此而言,实现此目标的最快方法是什么?

import pandas as pd
import numpy as np
import datetime

def dt_to_integer( dt_time):
    return 10000*dt_time.year + 100*dt_time.month + dt_time.day

def main_process():
 
    todays_date = datetime.datetime.now().date()
    index = pd.date_range( todays_date, periods=5, freq='D')
     
    columns = [ 'Volume', 'Volume1', 'Volume2']
     
    df_d = pd.DataFrame( index=index, columns=columns)
    df_d[ 'Volume'] = df_d.index.day * 100
    df_d[ 'Volume1'] = df_d.index.day * 500
    df_d[ 'Volume2'] = df_d.index.day * 1000

    todays_date = datetime.datetime.now().date()
    index = pd.date_range( todays_date, periods=1440, freq='5min')
     
    columns = [ 'Volume', 'Volume1', 'Volume2']
     
    df_i = pd.DataFrame( index=index, columns=columns)
    df_i = df_i.loc[ df_i.index.isin( df_i.between_time('09:30:00', '16:00:00').index)]
     
    for i in range( len( df_d)):
        the_date = dt_to_integer( df_d.index[i])
        
        df_i.Volume = np.where( dt_to_integer( df_i.index) == the_date, df_d.Volume[ i], df_i.Volume)
        df_i.Volume1 = np.where( dt_to_integer( df_i.index) == the_date, df_d.Volume1[ i], df_i.Volume1)
        df_i.Volume2 = np.where( dt_to_integer( df_i.index) == the_date, df_d.Volume2[ i], df_i.Volume2)
        
    return df_i, df_d

df_i, df_d = main_process()

问题在于,对于您的更新 for i in range(len( df_d)),您要为每次迭代更新完整的数据框,因此您的复杂度为 n1 * n2。可以做的改进结果是使用 numpy.searchsorted 找到 df_d 中的值插入 df_i 的索引,然后在插入的位置更新 df_i索引与现有索引相同。


def main_process2(n1=5, n2=1440):
 
    todays_date = datetime.datetime.now().date()
    index = pd.date_range( todays_date, periods=5, freq='D')
     
    columns = [ 'Volume', 'Volume1', 'Volume2']
     
    df_d = pd.DataFrame( index=index, columns=columns)
    df_d[ 'Volume'] = df_d.index.day * 100
    df_d[ 'Volume1'] = df_d.index.day * 500
    df_d[ 'Volume2'] = df_d.index.day * 1000

    todays_date = datetime.datetime.now().date()
    index = pd.date_range( todays_date, periods=1440, freq='5min')
     
    columns = [ 'Volume', 'Volume1', 'Volume2']
     
    df_i = pd.DataFrame( index=index, columns=columns)
    df_i = df_i.loc[ df_i.index.isin( df_i.between_time('09:30:00', '16:00:00').index)]
    
    the_dates = np.sort(dt_to_integer(df_d.index))
    the_indices = np.searchsorted(the_dates, dt_to_integer(df_i.index))
    # will give IndexError df_d has an index not present in df_i
    df_i.Volume = np.where( dt_to_integer( df_i.index) == the_dates[the_indices], df_d.Volume[the_indices], df_i.Volume)
    df_i.Volume1 = np.where( dt_to_integer( df_i.index) == the_dates[the_indices], df_d.Volume1[the_indices], df_i.Volume1)
    df_i.Volume2 = np.where( dt_to_integer( df_i.index) == the_dates[the_indices], df_d.Volume2[the_indices], df_i.Volume2)

    return df_i, df_d

正确性

我用

测试了输出
df_i, df_d = main_process()
df_i2, df_d2 = main_process2()
assert(np.max(np.abs(np.array(df_d) - np.array(df_d2))) == 0)
assert(np.max(np.abs(np.array(df_i) - np.array(df_i2))) == 0)

备选方案

实现略有不同


    # will give IndexError df_d has an index not present in df_i
    df_i.Volume[the_updated]  = np.array(df_d.Volume[the_indices[the_updated]])
    df_i.Volume1[the_updated] = np.array(df_d.Volume1[the_indices[the_updated]])
    df_i.Volume2[the_updated] = np.array(df_d.Volume2[the_indices[the_updated]])

或者一次线性更新所有列

    df_i.iloc[the_updated, :] = df_d.iloc[the_indices[the_updated], :]

性能

在提议的更改之后,main_process2(50, 14400),输入比您的示例大 10 倍,运行s 在 10-15 毫秒内,whyile main_process(50, 14400) 将在大约 13.5 内 运行秒。