我嘗試使用將附加到新 df 的 if 陳述句創建一個 for 回圈,但它沒有成功。我對此很陌生。
這段代碼是我嘗試的一種演算法,該演算法決定是否共享乘車,同時遵循許多約束。
match = []
for all rows in d12:
if d12.loc[d12['time_min']]-5 < d12['time_min'] < d12['time_min'] 5:
continue
else:
pass
if d12.loc[df11['distance_km']]-1 < d12['distance_km'] < d12['distance_km'] 1:
continue
else:
pass
if df12.loc[d12[sum['passenger_count']] <= 5:
match.append()
else:
pass
因此,它需要遍歷所有行并根據約束找到匹配項。每次在 2 行之間找到匹配項時,這兩個匹配的行都會進入一個名為 match[] 的資料框,其中包含所有相關列。如果沒有一個約束,它應該移到下一行。
完成后,這些匹配將從資料幀 d12 中洗掉。
約束詳細解釋:
1. time_min between both trips needs to be less or equal to 5 minutes.
2. distance_km between both trips has to be /-1km
3. A sum of passenger_count of two trips that are being combined has to be less or equal to 5.
4. A match can only be combined with two rows of the data.
資料示例:
| ID | time_min | distance_km | 乘客數 |
|---|---|---|---|
| 1 | 450 | 0.3 | 2 |
| 2 | 453 | 0.75 | 1 |
| 3 | 564 | 1.35 | 4 |
| 4 | 600 | 1.25 | 1 |
| 5 | 560 | 0.80 | 1 |
uj5u.com熱心網友回復:
嘗試使用自定義函式來查找可能的匹配項。然后通過是否找到匹配來過濾您的 DataFrame:
def find_match(row, df):
other = df.drop(row.name)
match = other[(other["time_min"].between(row["time_min"]-5,row["time_min"] 5, inclusive="both")) &
(other["distance_km"].between(row["distance_km"]-1,row["distance_km"] 1, inclusive="both")) &
(other["passenger_count"] row["passenger_count"]<=5)]
if match.shape[0]>0:
return match["ID"].iat[0]
return None
df["Match ID"] = df.apply(lambda row: find_match(row, df), axis=1)
match = df[df["Match ID"].notnull()].drop("Match ID", axis=1)
singles = df[df["Match ID"].isnull()].drop("Match ID", axis=1)
>>> match
ID time_min distance_km passenger_count
0 1 450 0.30 2
1 2 453 0.75 1
2 3 564 1.35 4
4 5 560 0.80 1
>>> singles
ID time_min distance_km passenger_count
3 4 600 1.25 1
uj5u.com熱心網友回復:
我以一種自然的方式處理了這個問題,并且可以輕松地自定義比較邏輯:
import pandas as pd
df = pd.DataFrame({
'time_min': [450, 453, 564, 600, 560],
'distance_km': [0.3, 0.75, 1.35, 1.25, 0.8],
'passenger_count': [2, 1, 4, 1, 1]
}, index=[1, 2, 3, 4, 5])
match = pd.DataFrame()
for idx1, first in df.iterrows():
for idx2, second in df.iterrows():
if idx1 <= idx2: # because a,b == b,a
continue
# your comparison logic goes here:
# 1. time_min between both trips needs to be less or equal to 5 minutes.
# 2. distance_km between both trips has to be /-1km
# 3. A sum of passenger_count of two trips that are being combined has to be less or equal to 5.
# 4. A match can only be combined with two rows of the data.
if (
abs(first['time_min'] - second['time_min']) <= 5
and abs(first['distance_km'] - second['distance_km']) <= 1
and first['passenger_count'] second['passenger_count'] <= 5
):
result = pd.DataFrame.from_dict([first, second])
match = pd.concat([match, result])
print(match)
uj5u.com熱心網友回復:
這是一種方法來做我相信你所問的,即:
- 識別可能的匹配項并填充一個名為
match - 從原始資料框中洗掉每一對匹配行的一行,注意不要洗掉任何給定行的多個可能匹配項
請注意,我們首先對輸入資料幀進行排序,time_min以便我們可以有效地識別與其中一個約束匹配的行(時間在 5 分鐘內的行),而無需對所有行與所有其他行進行完整的蠻力比較。
測驗用例包含比問題中更多的行,以顯示可能匹配的多于 2 行的情況下的行為:當我們遇到與其他 2 個或更多匹配的行時,我們將其洗掉并指定其中之一匹配的行存活(即不被洗掉)。
pandas as pd
d12 = pd.DataFrame([
[1, 450, 0.3, 2],
[2, 453, 0.75, 1],
[3, 564, 1.35, 4],
[4, 600, 1.25, 1],
[5, 560, 0.80, 1],
[6, 700, 1.26, 1],
[7, 701, 1.27, 1],
[8, 702, 1.28, 1],
[9, 703, 1.29, 1]
],
columns=[x.strip() for x in 'ID time_min distance_km passenger_count'.split()])
print("d12 in its initial state:")
print(d12)
df2 = d12.sort_values('time_min').reset_index(drop=True)
candidatesByIdx = []
minMax = [0, 0]
def foo(x):
i, j = minMax
while x.ID != df2.ID.iloc[i] and x.time_min - df2.time_min.iloc[i] > 5:
i = 1
while i >= 0 and x.time_min - df2.time_min.iloc[i] <= 5:
i -= 1
while j < len(df2.index) and df2.time_min.iloc[j] - x.time_min <= 5:
j = 1
minMax[:] = [i 1, j - 1]
L = []
for k in range(i 1, j):
if x.ID == df2.ID.iloc[k]:
continue
if abs(x.distance_km - df2.distance_km.iloc[k]) <= 1 and x.passenger_count df2.passenger_count.iloc[k] <= 5:
L.append(k)
return L
df2['cand_by_index'] = df2.apply(foo, axis=1)
print("df2 including temporary column cand_by_index:")
print(df2)
match = df2[df2['cand_by_index'].str.len() > 0].drop(columns=['cand_by_index'])
print("match is:")
print(match)
deleted = set()
do_not_delete = set()
def bar(x):
if x.index_copy not in do_not_delete:
already_processed = deleted | do_not_delete
for i in x.cand_by_index:
if i not in already_processed:
deleted.add(x.index_copy)
do_not_delete.add(i)
break
df2.assign(index_copy=df2.index).apply(bar, axis=1)
df2 = df2.drop(list(deleted)).drop(columns=['cand_by_index'])
print("copy of d12 with one row dropped from each matching pair:")
print(df2)
輸出:
d12 in its initial state:
ID time_min distance_km passenger_count
0 1 450 0.30 2
1 2 453 0.75 1
2 3 564 1.35 4
3 4 600 1.25 1
4 5 560 0.80 1
5 6 700 1.26 1
6 7 701 1.27 1
7 8 702 1.28 1
8 9 703 1.29 1
df2 including temporary column cand_by_index:
ID time_min distance_km passenger_count cand_by_index
0 1 450 0.30 2 [1]
1 2 453 0.75 1 [0]
2 5 560 0.80 1 [3]
3 3 564 1.35 4 [2]
4 4 600 1.25 1 []
5 6 700 1.26 1 [6, 7, 8]
6 7 701 1.27 1 [5, 7, 8]
7 8 702 1.28 1 [5, 6, 8]
8 9 703 1.29 1 [5, 6, 7]
match is:
ID time_min distance_km passenger_count
0 1 450 0.30 2
1 2 453 0.75 1
2 5 560 0.80 1
3 3 564 1.35 4
5 6 700 1.26 1
6 7 701 1.27 1
7 8 702 1.28 1
8 9 703 1.29 1
copy of d12 with one row dropped from each matching pair:
ID time_min distance_km passenger_count
1 2 453 0.75 1
3 3 564 1.35 4
4 4 600 1.25 1
6 7 701 1.27 1
8 9 703 1.29 1
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/468910.html
