具有多个条件的模糊连接



我知道那里有类似标题的问题,但没有一个真正回答我的问题。 我有一个数据框如下。"索引"列实际上是时间戳。A 列是向破碎机倾倒的物料数量。B 列是每个时间戳的破碎速率。我想知道的是何时根据破碎速率(B列(压碎材料(A列(。

有三种可能的情况。

  1. 当第二批装载时,第一个负载被压碎。
  2. 在第二次加载之前粉碎第一次加载
  3. 添加第二个负载时,第一个负载不会压碎

我尝试计算 A 列和 B 列的累积值,并使用merge_asof执行模糊连接。但它没有按预期工作,因为没有储存过多的破碎能力。只应考虑物料装载后的破碎速度。

A = {'index':range(1,11),'A':[300,0,0,400,0,0,0,0,150,0]}
B = {'index':range(1,11),'B':[102,103,94,120,145,114,126,117,107,100]}
A = pd.DataFrame(data=A)
B = pd.DataFrame(data=B)

以下是预期结果:

IndexA  A   IndexB  B_accumulate 
1      300  4       419
4      400  8       502
9      150  10      207

B_accumulate运行的总破碎速率(B(,当物料负载被压碎时(当B_accumlate>=A时(重置为0

我简化了结构,使用系列而不是数据帧,索引从零开始。 cumsum(( 和 searchsorted(( 被应用

Load = pd.Series([300,0,0,400,50,0,0,0,150,0])  # aka 'A'
Rate = pd.Series([102,103,94,120,145,114,126,117,107,100])  # aka 'B'
# Storage for the result:
H=[]    # [ (indexLoad, Load, indexRate, excess) ... ]
# Find the 1st non 0 load:
load1_idx= len(Load)
for lix in range(len(Load)):
a= Load[lix]
if a!=0:
csumser= Rate.cumsum()
rix= csumser.searchsorted(a)
excess= csumser[rix]-a
H.append( (lix,a,rix,excess) )
load1_idx=lix
break
# Processing
for lix in range(load1_idx+1,len(Load)):
a=Load[lix]
if a==0:
continue
last_rix= H[-1][-2]
csumser[last_rix:]= Rate[last_rix:]
if lix==last_rix:
csumser[lix]= H[-1][-1] # excess
csumser[last_rix:]= csumser[last_rix:].cumsum()
rix= csumser[last_rix:].searchsorted(a)
rix+= last_rix
excess= csumser[rix]-a
H.append( (lix,a,rix,excess) )       
df= pd.DataFrame(H, columns=["indexLoad","Load","indexRate","rate_excess"])
print(df)
indexLoad  Load  indexRate  rate_excess
0          0   300          3          119
1          3   400          6          104
2          4    50          6           76
3          8   150          7           93

这是一个非常详细的解决方案,我希望可以推广到您的完整数据。我相信你可以简化它。

C = A.join(B.set_index('index'), on='index')
C['A_filled'] = C['A'].replace(to_replace=0, method='ffill')
C['cumul_load'] = C['A'].cumsum()
C['load_number'] = C.groupby('cumul_load').ngroup() + 1
C['B_accum'] = C.groupby('load_number')['B'].cumsum()
C['A_fully_crushed'] = C['B_accum'] > C['A_filled']
C['first_index_fully_crushed'] = C.groupby('load_number')['A_fully_crushed'].cumsum() == 1
indexA_ = C['index'][C['A'] > 0].tolist()
A_ = C['A'][C['A'] > 0].tolist()
indexB_ = C['index'][C['first_index_fully_crushed'] == True].tolist()
B_accumulate_ = C['B_accum'][C['first_index_fully_crushed'] == True].tolist()
result = pd.DataFrame({'indexA': indexA_, 'A': A_, 'indexB': indexB_, 'B_accumulate': B_accumulate_})

这会产生

indexA    A  indexB  B_accumulate
0       1  300       4           419
1       6  400       9           464

创建DF组合A和B:

A = {'index':range(1,11),'A':[300,0,400,0,0,0,0,0,100,0]}
B = {'index':range(1,11),'B':[102,103,94,120,145,114,126,117,107,87]}
df_A = pd.DataFrame(data=A)
df_B = pd.DataFrame(data=B)
df_com = pd.concat([df_A,df_B],axis=1).drop('index',axis=1)

创建索引:

indexA = list(df_com.A[df_com.A.ne(0)].index + 1)
indexB = np.array(indexA) - 2
indexB = np.append(indexB[1:],(len(df_com)-1))

在 col A 中将 0 替换为 ffill((:

df_com['A'] = df_com.A.replace(0,method='pad')

分组依据和添加索引列:

df_new =df_com.groupby("A",sort=False).apply(lambda x:x.B.shift(1).sum()).reset_index()
df_new['indexA'] = indexA
df_new['indexB'] = indexB
df_new

可能的方法。该问题分为两部分 - 获取实际材料量(不能为负数(并分析载荷(当前时间步长内有任何材料量要粉碎时的行组(。

import numpy as np
import pandas as pd
def get_load(df):
""" get loaded material minus crushed material """
current_load = (df['A'] - df['B']).values
if current_load[0] < 0:
current_load[0] = 0
for idx in range(1, len(current_load)):
correct_value = current_load[idx - 1] + current_load[idx]
if correct_value < 0:
current_load[idx] = 0
else:
current_load[idx] = correct_value
return current_load
def get_work_load_chunk_stat(df):
""" get chunks when material actually crushing """
if df['load'].sum() == 0:
return
ans = pd.DataFrame(
{'indexA': [df.iloc[0, :]['indexA']],
'total_load': [df['A'].sum()],
'loads_qty': [df[df['A'] > 0]['A'].count()],
'indexB': [df.iloc[-1, :]['indexB']],
'total_work': [df['B'].sum()]})
return ans
if __name__ == '__main__':
A = {'indexA': range(22),
'A': [0, 300, 0, 0, 0, 0, 400, 0, 100, 0, 0, 0, 300, 0, 0, 0, 0, 400, 0, 100, 0, 0]}
B = {'indexB': range(22),
'B': [99, 102, 103, 94, 120, 145, 114, 126, 117, 107, 87, 99, 102, 103, 94, 120, 145, 114, 126, 117, 107, 87]}
data = pd.concat([pd.DataFrame(data=A), pd.DataFrame(data=B)], axis=1)
data['load'] = get_load(data)
data['load_check'] = np.where(data['load'] == 0, 1, 0)
data['load_check'] = data['load_check'].shift(fill_value=0).cumsum()
# print(data)
result = (
data
.groupby('load_check')
.apply(get_work_load_chunk_stat)
.reset_index(drop=True))
print(result)

输出:

indexA  total_load  loads_qty  indexB  total_work
0       1         300          1       4         419
1       6         500          2      10         551
2      12         300          1      15         419
3      17         500          2      21         551

最新更新