声明,本文译自 pandas with hundreds of millions of rows。 部分译者补充了部分内容。
问题
我们希望获得国内航班平均延误最长的 5 个美国机场。
此处的国内航班指的是美国国内航班
数据
我们使用了来自 Harvard Dataverse 的 Data Expo 2009: Airline on time data 数据集。该数据集包含从 1987 年 10 月到 2008 年 4 月美国境内所以商业航班降落和起飞的详细数据。 这大约有 1.2 亿条数据,分为 22 个 CSV 文件,每个 CSV 文件内包含 1 年的数据,以及 4 个我们不会使用的辅助 CSV 文件。 数据集解压后占用了大约 13 GB 硬盘空间。 原始数据集是经过压缩的,但解压缩部分不属于我们此次数据处理的任务。
原始数据集大概占用 1.3 GB 空间,使用 zip 压缩格式。
该数据集也在 《数据科学R语言实践》 此书中使用过。
环境
我使用以下硬件配置完成此项任务:
- Intel® Core™ i7-8550U CPU @ 1.80GHz
- 内存: LPDDR3 15820512 kB (16 Gb) 2133 MT/s, 无 swap
- 硬盘: KXG50ZNV512G NVMe TOSHIBA 512GB(使用 ext4 分区格式且未进行加密)
- 系统: Linux 5.19.9 (Arch 发行版, 仅运行 KDE Plasma 和单个 Konsole 会话, 占用 610 Mb 内存)
本文使用的软件配置如下:
幼稚方法
解决这一问题最简单的方法是直接使用 pandas
载入数据,代码如下:
import pandas
df = pandas.concat((pandas.read_csv(f'{
year}.csv') for year in range(1987, 2009)))
不幸的是,该方案会引发 MemoryError
(如果您使用 Jupyter 的话,此代码会导致内核重启)。 如果您的计算机存在大量内存,则不会出现此问题。 本文的其他部分将介绍一系列其他方式,使读者可以简单高效的完成此数据分析任务。
纯粹 Python 的方法
考虑到我们问题的特殊性,我们不需要将所有数据导入到内存中以计算每个机场的平均延迟。 我们可以读取数据行然后累加所需要的数据,即航班延迟和机场名称,然后丢弃此数据行。 当完成对所有数据行的读取后,我们获得了累加后的航班延迟,简单的与航班数量相除,我们就可以获得作为分析目标的平均值。
一个简单的实现如下:
import csv
import datetime
import heapq
import operator
USE_COLS = 'Origin', 'Year', 'Month', 'DayofMonth', 'CRSDepTime', 'DepTime'
airports = {
}
for year in rage(1987, 2009):
with open(f'../data/{
year}.csv', errors='ignore') as f:
reader = csv.reader(f)
header = {
name: position
for position, name
in enumerate(next(reader))
if name in USE_COLS}
for row in reader:
if row[header['CRSDepTime']] == 'NA' or row[header['DepTime']] == 'NA':
continue
year, month, day = (int(row[header['Year']]),
int(row[header['Month']]),
int(row[header['DayofMonth']]))
try:
scheduled_dep = datetime.datetime(year, month, day,
int(row[header['CRSDepTime']][:-2] or '0'),
int(row[header['CRSDepTime']][-2:]))
actual_dep = datetime.datetime(year, month, day,
int(row[header['DepTime']][:-2] or '0'),
int(row[header['DepTime']][-2:]))
except ValueError:
continue
delay = (actual_dep - scheduled_dep).total_seconds() / 3600.
if delay < -2.:
delay = 24. - delay