我想有條件地填充缺失并更新另一個資料框中的值。
我想填充缺失并更新dataframe smalldf中列值的資料。
條件是,如果B列(大 df )中的值在(小 df)列Range_FROM 和 Range_TO的范圍內。始終選擇 ( largedf ) 中的最小記錄來填充或更新smalldf中的值。
- 例如,在 smalldf值(3) 的第二條記錄中,由于 largedf 中有一個較小的值 (1.3),它最終會被較小的值 (1.3) 更新。
- 另一個例子,smalldf (Nan) 的第三條記錄被 1.6 填充,因為它是 Range_FROM (1.5) 和 Range_TO (1.6) 范圍內的最小值
這是第一個資料幀(smalldf):
| 路號 | 范圍 | Range_TO | 價值觀 |
|---|---|---|---|
| A001 | 1.15 | 1.2 | 0.1 |
| A001 | 1.35 | 1.4 | 3 |
| A001 | 1.55 | 1.6 | 楠 |
| A001 | 1.75 | 1.8 | 0.1 |
| A001 | 1.9 | 2 | 楠 |
這是第二個資料幀(largedf):
| 路號 | 乙 | 價值觀 |
|---|---|---|
| A001 | 1.1 | 0.2 |
| A001 | 1.2 | 0.1 |
| A001 | 1.3 | 1.9 |
| A001 | 1.4 | 1.3 |
| A001 | 1.5 | 1.6 |
| A001 | 1.6 | 1.9 |
| A001 | 1.7 | 0.2 |
| A001 | 1.8 | 0.1 |
| A001 | 1.9 | 1.9 |
| A001 | 2 | 1.3 |
以下是預期的資料框:
| 路號 | 范圍 | Range_TO | 價值觀 |
|---|---|---|---|
| A001 | 1.15 | 1.2 | 0.1 |
| A001 | 1.35 | 1.4 | 1.3 |
| A001 | 1.55 | 1.6 | 1.6 |
| A001 | 1.75 | 1.8 | 0.1 |
| A001 | 1.9 | 2 | 1.3 |
下面是創建兩個資料框的代碼:
smalldf = pd.DataFrame(data={"RoadNo":["A001", "A001", "A001", "A001", "A001"],
"Range_FROM": [1.15, 1.35, 1.55, 1.75, 1.9],
"Range_TO":[1.2, 1.4, 1.6, 1.8, 2],
"values": [0.1, 0.25, "Nan", 0.1, "Nan" ]})
largedf = pd.DataFrame(data={"RoadNo":["A001", "A001", "A001", "A001", "A001", "A001", "A001", "A001", "A001", "A001"],
"B": [1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2],
"values": [0.2, 0.1, 1.9, 1.3, 1.6, 1.9, 0.2, 0.1, 1.9, 1.3]})
請記住,還有其他 RoadNo(例如 A002、A003)。
pandas 中的 left join 和 fillna(df) 都沒有產生我想要的結果。Pandas 或 SQL 中是否有可以幫助我執行此操作的函式?
非常感謝!
uj5u.com熱心網友回復:
這是一種方法,根據 RoadNo 合并兩個 DF,然后過濾掉符合條件的 DF。最后用新值更新它們為空的值
df 中 Nan 的值被假定為 NaN,但有一個錯字。如果確實是 Nan,則可以在創建 df3 資料框的合并后將其轉換為 NaN,如下所示
df3['values'] = df3['values'].replace('Nan',np.nan ).astype(float)
df3=df.merge(df2, on='RoadNo', how='left', suffixes=('','_y')).query('(B >=Range_FROM) & (B<= Range_TO)')
df3['values'] = np.where((df3['values'].isnull()) | (df3['values'] > df3['values_y']) , df3['values_y'], df3['values'])
df3.drop(columns=['B','values_y'])
RoadNo Range_FROM Range_TO values
1 A001 1.15 1.2 0.1
13 A001 1.35 1.4 1.3
25 A001 1.55 1.6 1.9
37 A001 1.75 1.8 0.1
48 A001 1.90 2.0 1.9
49 A001 1.90 2.0 1.3
uj5u.com熱心網友回復:
在 SQL 中,您的問題如下所示:
SELECT df1.RoadNo, df1.Range_FROM, df1.Range_TO, MIN(df2.values)
FROM df1
LEFT JOIN df2
ON df1.RoadNo = df2.RoadNo
AND df2.B >= df1.Range_FROM
AND df2.B <= df1.Range_TO
GROUP BY df1.RoadNo, df1.Range_FROM, df1.Range_TO
所以我們可以這樣做:
from pandasql import sqldf
pysqldf = lambda q: sqldf(q, globals())
q = '''SELECT df1.RoadNo, df1.Range_FROM, df1.Range_TO, MIN(df2."values") AS "values"
FROM df1
LEFT JOIN df2
ON df1.RoadNo = df2.RoadNo
AND df2.B > df1.Range_LAG
AND df2.B <= df1.Range_TO
GROUP BY df1.RoadNo, df1.Range_FROM, df1.Range_TO'''
pysqldf(q)
df = pysqldf(q)
print(df)
輸出:
RoadNo Range_FROM Range_TO values
0 A001 1.15 1.2 0.1
1 A001 1.35 1.4 1.3
2 A001 1.55 1.6 1.9
3 A001 1.75 1.8 0.1
4 A001 1.90 2.0 1.3
但既然你真的想要一些不同的東西,讓我們試試:
df1['Range_LAG'] = df1.Range_TO.shift(fill_value=0)
q = '''SELECT df1.RoadNo, df1.Range_FROM, df1.Range_TO, MIN(df2."values") AS "values"
FROM df1
LEFT JOIN df2
ON df1.RoadNo = df2.RoadNo
AND df2.B > df1.Range_LAG
AND df2.B <= df1.Range_TO
GROUP BY df1.RoadNo, df1.Range_FROM, df1.Range_TO'''
df = pysqldf(q)
print(df)
輸出:
RoadNo Range_FROM Range_TO values
0 A001 1.15 1.2 0.1
1 A001 1.35 1.4 1.3
2 A001 1.55 1.6 1.6
3 A001 1.75 1.8 0.1
4 A001 1.90 2.0 1.3
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/496091.html
