gpt4 book ai didi

python pandas - 不同行的航类到达和离开时间 - 匹配并加入同一行然后绘制甘特图

转载 作者:行者123 更新时间:2023-11-30 22:37:29 25 4
gpt4 key购买 nike

假设我有一个这样的数据框(笔记本文本版本如下图):

A 是到达航类(着陆),D 是出发航类(起飞)。
Carrier 和 FltReg 一起是一架飞机.. 到达和离开一个机场,它会在几个小时或几天后再次返回同一个机场..
Acft 是飞机的类型。

到达和离开需要匹配,以便生成的数据框可用于计算和绘制甘特图(开始时间即到达时间和结束时间即起飞时间......航类在地面上的时间。)

数据通常会持续 7 天的航类时刻表和更多的承运人.. 7 天大约 3000 行...来自 sql server 数据库

enter image description here

from io import StringIO
import pandas as pd

dfstr = StringIO(u"""
ID;Car;FltNo;Acft;FltReg;E_FltType;Rtg;STADDtTm;ArrDep
0;EK;376;77W;A6ECI;T/A;DXB-BKK-DXB;03/05/2017 12:50;A
1;EK;377;77W;A6ECI;T/A;DXB-BKK-DXB;03/05/2017 15:40;D
2;EK;384;380;A6EDL;T/S;DXB-BKK-HKG;02/05/2017 12:15;A
3;EK;384;380;A6EDL;T/S;DXB-BKK-HKG;02/05/2017 14:00;D
4;EK;385;380;A6EDL;T/A;HKG-BKK-DXB;02/05/2017 23:45;A
5;EK;385;380;A6EDL;T/A;HKG-BKK-DXB;03/05/2017 01:15;D
54;VZ;920;320;HSVKA;DEP ONLY;BKK-HPH;01/05/2017 11:15;D
55;VZ;921;320;HSVKA;ARR ONLY;HPH-BKK;01/05/2017 15:25;A
56;VZ;602;320;HSVKA;DEP ONLY;BKK-CNX;01/05/2017 16:35;D
57;VZ;603;320;HSVKA;ARR ONLY;CNX-BKK;01/05/2017 19:45;A
58;VZ;602;320;HSVKA;DEP ONLY;BKK-CNX;02/05/2017 11:15;D
59;VZ;603;320;HSVKA;ARR ONLY;CNX-BKK;02/05/2017 14:25;A
60;VZ;820;320;HSVKA;DEP ONLY;BKK-HKT;03/05/2017 07:05;D
61;VZ;821;320;HSVKA;ARR ONLY;HKT-BKK;03/05/2017 15:45;A
62;VZ;828;320;HSVKA;DEP ONLY;BKK-HKT;03/05/2017 18:20;D
63;VZ;829;320;HSVKA;ARR ONLY;HKT-BKK;03/05/2017 21:50;A
64;VZ;600;320;HSVKB;DEP ONLY;BKK-CNX;01/05/2017 06:10;D
65;VZ;601;320;HSVKB;ARR ONLY;CNX-BKK;01/05/2017 09:20;A
66;VZ;606;320;HSVKB;DEP ONLY;BKK-CNX;01/05/2017 09:50;D
67;VZ;607;320;HSVKB;ARR ONLY;CNX-BKK;01/05/2017 13:00;A

""")
df = pd.read_csv(dfstr, sep=";", index_col='ID')
df

问题1:如何将上面的数据框转换为下面的。

如果 Car 和 FltReg 相同,我希望将其转换为相同的行。例如ID 0,EK376 A6ECI 于 5 月 3 日 12:50 抵达并以 ID 1 起飞,EK377 A6ECI 于 5 月 3 日 15:40... 同样适用于 ID2 和 3、ID4 和 5... 这些是 3 架不同的飞机,以粗体突出显示。其间还有许多其他航类……然后接下来是 ID54,它是一架带有 Aircraft Reg HSKVA 的 VZ 承运人……它首先起飞,所以它应该在自己的一排……然后它到达 ID55 并以 ID56 离开,并以 ID57 再次到达并以 ID58 离开。

以下是生成的数据框的外观: enter image description here
from io import StringIO
import pandas as pd

dfstr = StringIO(u"""
IDArr;Car;FltNo;Acft;FltReg;E_FltType;Rtg;STADDtTm;ArrDep;IDDep;Car;FltNo;Acft;FltReg;E_FltType;Rtg;STADDtTm;ArrDep
0;EK;376;77W;A6ECI;T/A;DXB-BKK-DXB;03/05/2017 12:50;A;1;EK;377;77W;A6ECI;T/A;DXB-BKK-DXB;03/05/2017 15:40;D
2;EK;384;380;A6EDL;T/S;DXB-BKK-HKG;02/05/2017 12:15;A;3;EK;384;380;A6EDL;T/S;DXB-BKK-HKG;02/05/2017 14:00;D
4;EK;385;380;A6EDL;T/A;HKG-BKK-DXB;02/05/2017 23:45;A;5;EK;385;380;A6EDL;T/A;HKG-BKK-DXB;03/05/2017 01:15;D
;;;;;;;;;54;VZ;920;320;HSVKA;DEP ONLY;BKK-HPH;01/05/2017 11:15;D
55;VZ;921;320;HSVKA;ARR ONLY;HPH-BKK;01/05/2017 15:25;A;56;VZ;602;320;HSVKA;DEP ONLY;BKK-CNX;01/05/2017 16:35;D
57;VZ;603;320;HSVKA;ARR ONLY;CNX-BKK;01/05/2017 19:45;A;58;VZ;602;320;HSVKA;DEP ONLY;BKK-CNX;02/05/2017 11:15;D
59;VZ;603;320;HSVKA;ARR ONLY;CNX-BKK;02/05/2017 14:25;A;60;VZ;820;320;HSVKA;DEP ONLY;BKK-HKT;03/05/2017 07:05;D
61;VZ;821;320;HSVKA;ARR ONLY;HKT-BKK;03/05/2017 15:45;A;62;VZ;828;320;HSVKA;DEP ONLY;BKK-HKT;03/05/2017 18:20;D
63;VZ;829;320;HSVKA;ARR ONLY;HKT-BKK;03/05/2017 21:50;A;;;;;;;;;
;;;;;;;;;64;VZ;600;320;HSVKB;DEP ONLY;BKK-CNX;01/05/2017 06:10;D
65;VZ;601;320;HSVKB;ARR ONLY;CNX-BKK;01/05/2017 09:20;A;66;VZ;606;320;HSVKB;DEP ONLY;BKK-CNX;01/05/2017 09:50;D
67;VZ;607;320;HSVKB;ARR ONLY;CNX-BKK;01/05/2017 13:00;A;;;;;;;;;

""")
df2 = pd.read_csv(dfstr, sep=";")
df2

如您所见...我们可以看到 ID0 和 ID1 在同一行匹配...因此更容易看到航类在地面上(即在机场)的时间...从 12:50 到15:40(2 小时 50 分钟)... 其余航类以此类推。

问题2:用上面生成的数据框制作甘特图

然后,此结果数据框将用于生成甘特图。

例如飞机:HSKVA(VZ 航类)将有自己的行...首先 11:15 出发(甘特图从 10:15(出发前 1 小时,因为没有到达)到 11:15 绘制。然后甘特图绘制15:25至16:35、19:45至次日11:15、14:25至07:05、15:45至18:20、21:50至22:50(航类到达后一小时)因为没有离开)。 matplotlib 的broken_barh 浮现在脑海

HSKVB 将有自己的甘特图行......等等。

每个航母/飞机注册在其自己的视觉行。

最佳答案

问题一

您的设置的一个快速更改是我没有设置 ID作为 index_col因为我想在 groupby().shift 中快速使用它的值.所以从修改后的read_csv开始:

df = pd.read_csv(dfstr, sep=";")
cols = df.columns.values.tolist()

解决方案的很大一部分是确保 df 按 Car 排序, FltReg , 和 STADDtTm (因为前两个是唯一标识符,最后一个是主排序值)。
sort_cols = ['Car', 'FltReg', 'STADDtTm']
df.sort_values(by=sort_cols, inplace=True)

所以现在我们处于逻辑的主要部分。我将 df 分为到达和离开,两者的连接方式是 转移 ID .也就是说,对于任何( CarFltReg )分区,我知道将给定的“A”行与紧随其后的“D”行配对。再说一次,这就是我们需要排序(和完整)数据的原因。

让我们生成转换后的 ID:
# sort_cols[:2] is `Car` and `FltReg` together
df['NextID'] = df.groupby(sort_cols[:2])['ID'].shift(1)

现在使用“A”过滤的 df 和“D”过滤的 df,我将它们完全外连接在一起。到达(左侧数据集)由原始 ID 键入。 ,而离开(右数据集)由 NextID 键入我们刚做的。
df_display = df[df['ArrDep'] == 'A'] \
.merge(df[df['ArrDep'] == 'D'],
how='outer',
left_on='ID',
right_on='NextID',
suffixes=('1', '2'))

请注意,这些列现在将以 1 为后缀。 (左)和 2 (正确的)。

此时,这个新的数据框 df_display有它需要的所有行,但它在你的最终显示中没有很好的排序。为此,您需要 sort_cols再次列出,但每个列的合并版本将各自的左右版本放在一起。例如, Car1Car2必须合并在一起,以便您可以排序 所有行 通过组合版本。

Pandas ' combine_first就像合并。
# purely for sorting the final display
for c in sort_cols:
df_display['sort_' + c] = df_display[c + '1'] \
.combine_first(df_display[c + '2'])
# for example, Car1 and Car2 have now been coalesced into sort_Car

df_display.sort_values(by=['sort_{}'.format(c) for c in sort_cols], inplace=True)

我们快完成了。现在 df_display有我们不需要的多余列。我们可以只选择我们想要的列——基本上,原始列列表的两个副本 cols .
df_display = df_display[['{}1'.format(c) for c in cols] + ['{}2'.format(c) for c in cols]]
df_display.to_csv('output.csv', index=None)

我检查了(在 csv 导出中,以便我们可以看到广泛的数据集)这与您的样本匹配。

output

问题2

好的,所以如果你在 https://matplotlib.org/examples/pylab_examples/broken_barh.html 上玩代码, 你可以看看 broken_barh运作。这很重要,因为我们必须使数据适合这个结构才能使用它。 broken_barh的第一个参数是要绘制的元组列表,每个元组是一个(开始时间,持续时间)。

对于 matplotlib,开始时间必须采用其特殊的日期格式。所以我们必须使用 matplotlib.dates.date2num 转换 pandas 日期时间。 .最后,持续时间似乎以天为单位。

因此,如果 HSVKA 于 2017-05-01 15:25:00 到达并在地面上停留 70 分钟,则 broken_barh需要绘制元组 (mdates.date2num(Timestamp('2017-05-03 15:25:00')), 70 minutes in day units or 0.04861) .

所以第一步是获取 df_display来自 问题一以这种格式。我们只需要关注这四列 'Car1', 'FltReg1', 'STADDtTm1', 'STADDtTm2'现在。
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import seaborn # optional ... I like the look

print(df_display[['Car1', 'FltReg1', 'STADDtTm1', 'STADDtTm2']])

看起来像
   Car1 FltReg1         STADDtTm1         STADDtTm2
0 EK A6ECI 03/05/2017 12:50 03/05/2017 15:40
1 EK A6EDL 02/05/2017 12:15 02/05/2017 14:00
2 EK A6EDL 02/05/2017 23:45 03/05/2017 01:15
10 NaN NaN NaN 01/05/2017 11:15
3 VZ HSVKA 01/05/2017 15:25 01/05/2017 16:35
4 VZ HSVKA 01/05/2017 19:45 02/05/2017 11:15
5 VZ HSVKA 02/05/2017 14:25 03/05/2017 07:05
6 VZ HSVKA 03/05/2017 15:45 03/05/2017 18:20
7 VZ HSVKA 03/05/2017 21:50 NaN
11 NaN NaN NaN 01/05/2017 06:10
8 VZ HSVKB 01/05/2017 09:20 01/05/2017 09:50
9 VZ HSVKB 01/05/2017 13:00 NaN

NaN s 缺少到达或离开时。估算这些是相当简单的。我在您的文章中注意到,当缺少某些东西时,您希望两边都有一小时的缓冲区。所以这就是所有这些简单的争论:
df_gantt = df_display.copy()

# Convert to pandas timestamps for date arithmetic
df_gantt['STADDtTm1'] = pd.to_datetime(df_gantt['STADDtTm1'],
format='%d/%m/%Y %H:%M')
df_gantt['STADDtTm2'] = pd.to_datetime(df_gantt['STADDtTm2'],
format='%d/%m/%Y %H:%M')

# Impute identifiers
df_gantt['Car'] = df_gantt['Car1'].combine_first(df_gantt['Car2'])
df_gantt['FltReg'] = df_gantt['FltReg1'].combine_first(df_gantt['FltReg2'])

# Also just gonna combine Car and FltReg
# into a single column for simplicty
df_gantt['Car_FltReg'] = df_gantt['Car'] + ': ' + df_gantt['FltReg']

# Impute hour gaps
df_gantt['STADDtTm1'] = df_gantt['STADDtTm1'] \
.fillna(df_gantt['STADDtTm2'] - pd.Timedelta('1 hour'))
df_gantt['STADDtTm2'] = df_gantt['STADDtTm2'] \
.fillna(df_gantt['STADDtTm1'] + pd.Timedelta('1 hour'))

# Date diff in day units
df_gantt['DayDiff'] = (df_gantt['STADDtTm2'] - df_gantt['STADDtTm1']).dt.seconds \
/ 60 / 60 / 24

# matplotlib numeric date format
df_gantt['STADDtTm1'] = df_gantt['STADDtTm1'].apply(mdates.date2num)
df_gantt['STADDtTm2'] = df_gantt['STADDtTm2'].apply(mdates.date2num)

df_gantt = df_gantt[['Car_FltReg', 'STADDtTm1', 'STADDtTm2', 'DayDiff']]
print(df_gantt)

现在看起来像
   Car_FltReg      STADDtTm1      STADDtTm2   DayDiff
0 EK: A6ECI 736452.534722 736452.652778 0.118056
1 EK: A6EDL 736451.510417 736451.583333 0.072917
2 EK: A6EDL 736451.989583 736452.052083 0.062500
10 VZ: HSVKA 736450.427083 736450.468750 0.041667
3 VZ: HSVKA 736450.642361 736450.690972 0.048611
4 VZ: HSVKA 736450.822917 736451.468750 0.645833
5 VZ: HSVKA 736451.600694 736452.295139 0.694444
6 VZ: HSVKA 736452.656250 736452.763889 0.107639
7 VZ: HSVKA 736452.909722 736452.951389 0.041667
11 VZ: HSVKB 736450.215278 736450.256944 0.041667
8 VZ: HSVKB 736450.388889 736450.409722 0.020833
9 VZ: HSVKB 736450.541667 736450.583333 0.041667

现在制作一个字典,其中每个键都是唯一的 Car_FltReg每个值都是一个元组列表(如前所述),可以输入 broken_barh .
dict_gantt = df_gantt.groupby('Car_FltReg')['STADDtTm1', 'DayDiff'] \
.apply(lambda x: list(zip(x['STADDtTm1'].tolist(),
x['DayDiff'].tolist()))) \
.to_dict()

所以 dict_gantt好像
{'EK: A6ECI': [(736452.5347222222, 0.11805555555555557)],
'EK: A6EDL': [(736451.5104166666, 0.07291666666666667),
(736451.9895833334, 0.0625)],
'VZ: HSVKA': [(736450.4270833334, 0.041666666666666664),
(736450.6423611111, 0.04861111111111111),
(736450.8229166666, 0.6458333333333334),
(736451.6006944445, 0.6944444444444445),
(736452.65625, 0.1076388888888889),
(736452.9097222222, 0.041666666666666664)],
'VZ: HSVKB': [(736450.2152777778, 0.041666666666666664),
(736450.3888888889, 0.020833333333333332),
(736450.5416666666, 0.041666666666666664)]}

非常适合 broken_barh .现在这都是 matplotlib 的疯狂。核心逻辑后准备 broken_barh东西,其他的只是费力的刻度格式等。如果你在 matplotlib 中自定义了一些东西,这些东西应该很熟悉——我不会解释太多。
FltReg_list = sorted(dict_gantt, reverse=True)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

start_datetime = df_gantt['STADDtTm1'].min()
end_datetime = df_gantt['STADDtTm2'].max()

# parameters for yticks, etc.
# you might have to play around
# with the different parts to modify
n = len(FltReg_list)
bar_size = 9

for i, bar in enumerate(FltReg_list):
ax.broken_barh(dict_gantt[bar], # data
(10 * (i + 1), bar_size), # (y position, bar size)
alpha=0.75,
edgecolor='k',
linewidth=1.2)

# I got date formatting ideas from
# https://matplotlib.org/examples/pylab_examples/finance_demo.html
ax.set_xlim(start_datetime, end_datetime)
ax.xaxis.set_major_locator(mdates.HourLocator(byhour=range(0, 24, 6)))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d %H:%M'))
ax.xaxis.set_minor_locator(mdates.HourLocator(byhour=range(0, 24, 1)))
# omitting minor labels ...

plt.grid(b=True, which='minor', color='w', linestyle='dotted')

ax.set_yticks([5 + 10 * n for n in range(1, n + 1)])
ax.set_ylim(5, 5 + 10 * (n + 1))
ax.set_yticklabels(FltReg_list)

ax.set_title('Time on Ground')
ax.set_ylabel('Carrier: Registration')

plt.setp(plt.gca().get_xticklabels(), rotation=30, horizontalalignment='right')

plt.tight_layout()
fig.savefig('gantt.png', dpi=200)

这是最终的输出。

gantt

关于python pandas - 不同行的航类到达和离开时间 - 匹配并加入同一行然后绘制甘特图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43876089/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com