我有兩個值的資料集(df1和df2),它們都具有一定范圍(Start和End)。
我想df1用Num相應重疊值范圍 ( Start/ End) 上的列中的值來注釋第一個 ( ) df2。
實施例:在第一行df1從范圍0- 2300000,由于2300000是比下End在第一行df2和整個范圍0-2300000與的范圍重疊62920- ,121705338將它與帶注釋Num 3。類似地,同樣的行的2df1已范圍2300000-5400000與的范圍重疊62920- 121705338,行2也將與注釋Num 3。
然而,在最后一排的情況下df1,范圍包含兩行df2,所以需要有輸出的總和中Num的最后兩行df2。
所需的輸出將是 df3
df1.head()
|Start |End |Tag |
|---------|---------|-------|
|0 |2300000 |gneg45 |
|2300000 |5400000 |gpos25 |
|143541857|200000000|gneg34 |
df2.head()
| Start | End | Num |
|---------|---------|--------|
|62920 |121705338| 3 |
|143541857|147901334| 2 |
|147901760|151020217| 5 |
df3 =
|Start |End |Num |
|---------|---------|-------|
|0 |2300000 |3 |
|2300000 |5400000 |3 |
|143541857|200000000|7 |
我嘗試過熊貓merge創建一個鍵并query基于一系列列,但沒有任何效果。
提前致謝!!
uj5u.com熱心網友回復:
從你的描述,你正在尋找的重疊范圍df1,并df2為了df1采取Num從df2。
為了制定重疊范圍條件的條件,我們將非重疊范圍的條件說明如下:
任何一個:
|<-------------->|
df2.Start .df2.End
|<------------->|
df1.Start df1.End
或者:
|<-------------->|
df2.Start .df2.End
|<------------->|
df1.Start df1.End
這種非重疊范圍條件可以表述為:
( df1.End< df2.Start) 或 ( df1.Start> df2.End)
因此,重疊范圍條件是上述條件的否定,即:
~ (( df1.End< df2.Start) | ( df1.Start> df2.End))
這相當于:
( df1.End>= df2.Start) & ( df1.Start<= df2.End)
解決方案 1:針對小資料集的簡單解決方案
Step 1:對于小資料集,可以交叉連接df1和df2by .merge(),然后使用 的重疊條件過濾.query(),如下:
df3 = (df1.merge(df2, how='cross', suffixes=('_df1', '_df2'))
.query('(End_df1 >= Start_df2) & (Start_df1 <= End_df2)')
.rename({'Start_df1': 'Start', 'End_df1': 'End'}, axis=1)
[['Start', 'End', 'Num']]
)
如果您的 Pandas 版本早于 1.2.0(2020 年 12 月發布)并且不支持與 合并how='cross',您可以使用:
df3 = (df1.assign(key=1).merge(df2.assign(key=1), on='key', suffixes=('_df1', '_df2')).drop('key', axis=1)
.query('(End_df1 >= Start_df2) & (Start_df1 <= End_df2)')
.rename({'Start_df1': 'Start', 'End_df1': 'End'}, axis=1)
[['Start', 'End', 'Num']]
)
中間結果:
print(df3)
Start End Num
0 0 2300000 3
3 2300000 5400000 3
7 143541857 200000000 2
8 143541857 200000000 5
步驟2: 總結Num值相同的范圍(同Start和End)由.groupby()和.sum():
df3 = df3.groupby(['Start', 'End'])['Num'].sum().reset_index()
結果:
print(df3)
Start End Num
0 0 2300000 3
1 2300000 5400000 3
2 143541857 200000000 7
解決方案 2:針對大型資料集的 Numpy 解決方案
對于大型資料集和性能是一個問題,您可以使用numpy 廣播(而不是交叉連接和過濾)來加快執行時間:
第1步:
d1_S = df1.Start.to_numpy()
d1_E = df1.End.to_numpy()
d2_S = df2.Start.to_numpy()
d2_E = df2.End.to_numpy()
# filter for overlapping range condition and get the respective row indexes of `df1`, `df2` in `i` and `j`
i, j = np.where((d1_E[:, None] >= d2_S) & (d1_S[:, None] <= d2_E))
df3 = pd.DataFrame(
np.column_stack([df1.values[i], df2.values[j]]),
columns=df1.columns.append(df2.columns '_df2')
)
中間結果:
print(df3)
Start End Tag Start_df2 End_df2 Num_df2
0 0 2300000 gneg45 62920 121705338 3
1 2300000 5400000 gpos25 62920 121705338 3
2 143541857 200000000 gneg34 143541857 147901334 2
3 143541857 200000000 gneg34 147901760 151020217 5
步驟2: 總結Num值相同的范圍(同Start和End)由.groupby()和.sum():
df3 = df3.groupby(['Start', 'End'])['Num_df2'].sum().reset_index(name='Num')
結果:
print(df3)
Start End Num
0 0 2300000 3
1 2300000 5400000 3
2 143541857 200000000 7
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/333455.html
下一篇:按特定列值對資料框進行分組
