【问题标题】:How do I update 3 columns of dataframe A with 3 respective columns of dataframe B with one np.where statement如何使用一个 np.where 语句更新数据框 A 的 3 列和数据框 B 的 3 列
【发布时间】:2021-02-10 16:50:13
【问题描述】:

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

我在 df_d 中有 3 列(Volume、Volume1 和 Volume2),我想在各个日期传播到 df_i。 p>

当我调用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()

【问题讨论】:

标签: dataframe numpy array-broadcasting


【解决方案1】:

问题在于,对于您的更新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 倍,运行时间为 10-15 毫秒,whyile main_process(50, 14400) 将在大约 13.5 秒内运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-23
    • 2020-07-09
    • 2021-11-02
    • 2022-11-13
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 2019-10-26
    相关资源
    最近更新 更多