У меня есть четыре таблицы производства графика авиакомпании. На самом деле у меня нет колонки PK, но я помещаю ее туда, чтобы легче справляться с полетами. Сейчас я их в pd.DataFrames.
Таблица 1. Проект №1
MarketID Origin Dest FltNum DepCentral ArrCentral PK
1DFWSJC DFW SJC 111 0700 1035 A
2DFWSJC DFW SJC 222 2035 2410 B
Таблица 2. Проект №2
MarketID Origin Dest FltNum DepCentral ArrCentral PK
1DFWSJC DFW SJC 111 0700 1030 A
2DFWSJC DFW SJC 222 2040 2410 B
Таблица 3. Проект № 3
MarketID Origin Dest FltNum DepCentral ArrCentral PK
1DFWSJC DFW SJC 444 0645 1015 A
2DFWSJC DFW SJC 555 1300 1630 X
3DFWSJC DFW SJC 666 2040 2410 B
Таблица 4. Окончательный график
MarketID Origin Dest FltNum DepCentral ArrCentral PK
1DFWSJC DFW SJC 444 0645 1015 A
2DFWSJC DFW SJC 666 2040 2415 B
Я в основном хочу следить за каждым рейсом, который был в проекте 1, который также находится в конечном графике, и посмотреть, как они были изменены в процессе производства. Но я также пытаюсь отслеживать изменения, внесенные в каждый полет через каждый стол. По существу это было бы внутреннее соединение, и у меня были бы столбцы для DepCentral_Draft1, DepCentral_Draft2 и т.д.
С этим я мог видеть, что между проектами 1 и 2 полет A имел время своего прибытия, перемещенное на 5 минут раньше. Между осадками 2 и 3 полет A имел время вылета и прибытия, перемещенное на 15 минут раньше. и т.п.
MarketID приближается, но между черновиками № 2 и № 3 они вставили рейс и повторно обозначенный MarketID (он был заказан по времени отправления). Похоже, что они добавили и вычитали полеты довольно бесцеремонно между Draft # 2 и # 3, а также между № 3 и Final, поэтому я не могу полагаться на MarketID.
FltNum также очень непоследователен. Между Draft # 1 и # 2 они совпадают, но # 3 и # 4, они кажутся случайным образом заменяют номер рейса после Draft # 3.
Как человек я могу сказать, что 2DFWSJC в таблице 3 не является ни полетом А, ни В из-за того, насколько отличается его время вылета/прибытия. Когда я присоединился к MarketID, он думал, что перелет B перемещается с 2040 до 1300 (именно так я заметил эти вставки).
Я не могу объединить Origin, Dest, и время отправления или прибытия, и матч, потому что они немного смещены, поэтому они не являются точными совпадениями. Я видел нечеткие сравнения со строками, но я не видел ничего подобного с числами.
Что-то вроде определения полета B как
Origin = DFW
Dest = SJC
DepCentral = ~2035
ArrCentral = ~2410
Где я мог бы определить, насколько близко ~, или автоматически понимает, что 2040 намного ближе к 2035 году, чем 1300, и присоединяется, если это возможно.
Это оригинальная функция, которую я написал, чтобы найти разницу между исходным расписанием и новым.
def schdChanges(base, new):
merged = pd.merge(base, new, on = ['MktSegID'])
diffDf = pd.DataFrame()
diffDf['MktSegID'] = merged['MktSegID']
diffDf['Cdep'] = merged['Cdep_y'] - merged['Cdep_x']
diffDf['Carr'] = merged['Carr_y'] - merged['Carr_x']
diffDf['Block'] = merged['Block_y'] - merged['Block_x']
diffDf['Turn'] = merged['Turn_y'] - merged['Turn_x']
return diffDf
Редактировать. Альтернативные решения, которые у меня были, определяют, где изменилась емкость рынка (например, DFW-SJC), и сосредоточена только на них.
DirMkt - Origin + Dest
Draft1Cap = Draft1.groupby('DirMkt')['MktSegID'].nunique()
FinalCap = Final.groupby( 'DirMkt')['MktSegID'].nunique()
FinalCap.subtract(Draft1Cap, fill_value = 0)[FinalCap.subtract(Draft1Cap, fill_value = 0) != 0]
Итак, теперь я определил, какие из них изменились. Моя старая функция работает на все, кроме этих.
И используя это, я определил, какие рынки нужно удалить из графика, потому что они не существуют ни в черновике, ни в финале
def returnNotMatches(a, b):
return [[x for x in a if x not in b], [x for x in b if x not in a]]
returnNotMatches(set(Draft1['DirMkt'].unique()), set(Final['DirMkt'].unique()))
Итак, в основном, минимальный минимум, который мне нужен, - это выяснить, когда добавляется полет, где он был добавлен по отношению к другим рейсам на его рынке?
У вас 6 столбцов. Позвольте разбить их на то, насколько они полезны в этой ситуации.
MarketID
и FltNum
могут меняться произвольно, так что это нам не поможет. Origin
and Dest
Я предполагаю, что он должен быть одним и тем же и не может измениться, поэтому мы проверим, что DepCentral
и ArrCentral
являются наиболее важными, и каждый из них может изменить до 50 минут.
У вас есть сложная бизнес-логика, поэтому, вероятно, это не простое решение. Итак, здесь, где приходит удовольствие, кодируя что-то, чтобы справиться с этой логикой!
Эта программа находит совпадения, я оставлю это до вас, чтобы получить результат, как вам это понравится
import pandas as pd
Если у вас есть даты или вы точно знаете, что у вас не будет чего-то в 23:55, которое должно совпадать с 00:04, вы можете упростить или заменить эту логику
def time_change(old_time, new_time):
old_hrs, new_hrs = int(old_time[0:2]), int(new_time[0:2])
old_mins, new_mins = int(old_time[2:]), int(new_time[2:])
old_total = 60 * old_hrs + old_mins
new_total = 60 * new_hrs + new_mins
# note, this may make incorrect assumptions since we don't have the day.
# If you have the day in your actual data, there are better ways of comparing the times
return abs((new_total - old_total)) % (24 * 60)
теперь, к сути дела, проверяя матч. Вы изложили то, что ищете, так что это всего лишь логика его реализации. Эта функция принимает любые две строки для сравнения.
def check_match(old, new):
#["MarketID", "Origin", "Dest", "FltNum", "DepCentral", "ArrCentral"]
if old['Origin'] != new['Origin']:
return False, "", ""
if old['Dest'] != new['Dest']:
return False, "", ""
total_time_change = time_change(old["DepCentral"], new["DepCentral"]) + \
time_change(old["ArrCentral"], new["ArrCentral"])
if abs(total_time_change) <= 50:
return True, total_time_change, "other fields that changed"
else:
return False, "", ""
Прокрутите все строки в старой и новой таблице и сравните их. С размером данных, о которых вы упомянули, смотреть все должно быть хорошо.
def compare_tables(old, new_df):
if 'PK' not in old.columns:
# use the current index as the starting PK
old['PK'] = old.index
for _, old_row in old.iterrows():
print("Looking at row:")
print(old_row.T)
pk = old_row['PK']
best_match = None
best_match_time_change = float('inf')
for _, new_row in new_df.iterrows():
is_match, time_change, old_changes = check_match(old_row, new_row)
if is_match and (time_change < best_match_time_change):
best_match_time_change = time_change
best_match = new_row
print("The best match is:")
if best_match is not None:
print(best_match.T, best_match_time_change)
else:
print("no matches found")
print()
print()
петля через все пары таблиц:
all_tables = [table_1, table_2, table_3, table_4]
for old, new_df in zip(all_tables, all_tables[1:]):
compare_tables(old, new_df)