如何使用一个 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 内 运行秒。
在下面的代码中,我创建了包含每日数据的 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 内 运行秒。