基于地铁刷卡数据分析与可视化——以杭州市为例(二)

上篇文章提到,由于2019年1月1日正好是元旦,为了消除节假日对数据分析的影响,我们选择了节后的一周来进行详细的客流分析。具体日期选择为2019年1月8日至1月14日。在这段时间内,我们关注的是地铁线路的进站客流情况。数据表中的 'status' 字段表示进出站状态,其中0代表出站,1代表进站。我们的目标是计算这一周内三条地铁线路(A线、B线和C线)的平均进站客流量,以全面了解各线路的客流分布和高峰时段的特点;

完整代码#运行环境Python 3.11

python 复制代码
# -*- coding: utf-8 -*-

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号

# 文件路径列表
file_paths = [
    'D:\\data\\record_2019-01-08.csv',
    'D:\\data\\record_2019-01-09.csv',
    'D:\\data\\record_2019-01-10.csv',
    'D:\\data\\record_2019-01-11.csv',
    'D:\\data\\record_2019-01-12.csv',
    'D:\\data\\record_2019-01-13.csv',
    'D:\\data\\record_2019-01-14.csv'
]

# 存储每个日期的每小时客流量
daily_hourly_counts = []

# 读取每个CSV文件并计算每小时客流量
for file_path in file_paths:
    df = pd.read_csv(file_path)

    # 确保 'time' 列是 datetime 类型
    df['time'] = pd.to_datetime(df['time'])

    # 筛选条件:'lineID' = 'A' 且 'status' = 1
    filtered_df = df[(df['lineID'] == 'A') & (df['status'] == 1)]

    # 按 'time' 和 'stationID' 分组,并按小时汇总客流量
    hourly_station_customer_count = filtered_df.groupby([filtered_df['time'].dt.hour, 'stationID']).size().unstack(fill_value=0)

    # 将结果存储到列表中
    daily_hourly_counts.append(hourly_station_customer_count)

# 合并所有日期的每小时客流量
combined_hourly_counts = pd.concat(daily_hourly_counts, axis=0)

# 计算每个小时各个 stationID 的平均客流量
average_hourly_station_customer_count = combined_hourly_counts.groupby(combined_hourly_counts.index).mean()

# 打印结果
print("每个小时各个 'stationID' 的平均客流量:")
print(average_hourly_station_customer_count)

# 可视化
plt.figure(figsize=(14, 7))

# 为每个 stationID 绘制折线图
for station in average_hourly_station_customer_count.columns:
    plt.plot(average_hourly_station_customer_count.index, average_hourly_station_customer_count[station], label=f'Station {station}')

# 设置图表标题和标签
plt.title('每个小时各个 stationID 的平均客流量')
plt.xlabel('小时')
plt.ylabel('平均客流量')
plt.legend()
plt.grid(True)

# 显示图表
plt.show()

我们通过编写Python脚本来计算全天24小时内各个站点的进站客流量变化情况,并进一步对一周内的客流量数据求均值,以全面了解各站点的客流量分布特点;

A线路各个站点在全天的平均进站客流量分布情况

B线路各个站点在全天的平均进站客流量分布情况

C线路各个站点在全天的平均进站客流量分布情况

我们把数据的研究尺度进一步缩小,同样的,我们通过python脚本来计算一下,全天24小时的各个站点进站客流的早晚高峰峰值区间分布情况,并对一周的客流量求均值,我们来看各线路早晚高峰的15分钟峰值客流分布情况;

完整代码#运行环境Python 3.11

python 复制代码
# -*- coding: utf-8 -*-

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号


def read_and_process_file(file_path):
    try:
        df = pd.read_csv(file_path)
        df['time'] = pd.to_datetime(df['time'])
        filtered_df = df[(df['lineID'] == 'A') & (df['status'] == 1)]
        # 按15分钟分组
        fifteen_minute_station_customer_count = filtered_df.groupby(
            [pd.Grouper(key='time', freq='15min'), 'stationID']).size().unstack(fill_value=0)
        return fifteen_minute_station_customer_count
    except Exception as e:
        print(f"Error processing file {file_path}: {e}")
        return None


# 文件路径列表
file_paths = [
    'D:\\data\\record_2019-01-08.csv',
    'D:\\data\\record_2019-01-09.csv',
    'D:\\data\\record_2019-01-10.csv',
    'D:\\data\\record_2019-01-11.csv',
    'D:\\data\\record_2019-01-12.csv',
    'D:\\data\\record_2019-01-13.csv',
    'D:\\data\\record_2019-01-14.csv'
]

# 存储每个日期的每15分钟客流量
daily_fifteen_minute_counts = []

# 读取每个CSV文件并计算每15分钟客流量
for file_path in file_paths:
    fifteen_minute_station_customer_count = read_and_process_file(file_path)
    if fifteen_minute_station_customer_count is not None:
        daily_fifteen_minute_counts.append(fifteen_minute_station_customer_count)

# 合并所有日期的每15分钟客流量
combined_fifteen_minute_counts = pd.concat(daily_fifteen_minute_counts, axis=0)

# 计算每15分钟各个 stationID 的平均客流量
average_fifteen_minute_station_customer_count = combined_fifteen_minute_counts.groupby(
    combined_fifteen_minute_counts.index.time).mean()

# 将索引转换为 DatetimeIndex
average_fifteen_minute_station_customer_count.index = pd.to_datetime(
    average_fifteen_minute_station_customer_count.index, format='%H:%M:%S')

# 打印结果
print("每15分钟各个 'stationID' 的平均客流量:")
print(average_fifteen_minute_station_customer_count)

# 确定早高峰和晚高峰15分钟区间
peak_intervals = {}
for station in average_fifteen_minute_station_customer_count.columns:
    # 早高峰时间段
    morning_peak = average_fifteen_minute_station_customer_count.between_time('06:00', '10:00')[station].idxmax()
    # 晚高峰时间段
    evening_peak = average_fifteen_minute_station_customer_count.between_time('16:00', '20:00')[station].idxmax()

    formatted_morning_peak = f"{morning_peak.strftime('%H:%M')}-{(morning_peak + pd.Timedelta(minutes=15)).strftime('%H:%M')}"
    formatted_evening_peak = f"{evening_peak.strftime('%H:%M')}-{(evening_peak + pd.Timedelta(minutes=15)).strftime('%H:%M')}"

    peak_intervals[station] = {
        'morning': formatted_morning_peak,
        'evening': formatted_evening_peak
    }

# 输出每个站点的早高峰和晚高峰15分钟区间
print("\n各站点早高峰和晚高峰进站客流的15分钟区间:")
for station, intervals in peak_intervals.items():
    print(f"Station {station}: 早高峰 {intervals['morning']}, 晚高峰 {intervals['evening']}")

# 可视化
fig, ax = plt.subplots(figsize=(14, 8))

# 为每个 stationID 绘制24小时刻度图
cmap = plt.get_cmap('tab10')  # 获取颜色映射
colors = [cmap(i % cmap.N) for i in range(len(peak_intervals))]

for i, (station, intervals) in enumerate(peak_intervals.items()):
    # 早高峰
    start_time, end_time = intervals['morning'].split('-')
    start_hour = int(start_time[:2]) + int(start_time[3:]) / 60
    end_hour = int(end_time[:2]) + int(end_time[3:]) / 60
    ax.axvspan(start_hour, end_hour, alpha=0.3, color=colors[i],
               label=f'Station {station} 早高峰 {intervals["morning"]}')

    # 晚高峰
    start_time, end_time = intervals['evening'].split('-')
    start_hour = int(start_time[:2]) + int(start_time[3:]) / 60
    end_hour = int(end_time[:2]) + int(end_time[3:]) / 60
    ax.axvspan(start_hour, end_hour, alpha=0.3, color=colors[i],
               label=f'Station {station} 晚高峰 {intervals["evening"]}')

# 设置图表标题和标签
ax.set_title('各站点早高峰和晚高峰进站客流的15分钟区间')
ax.set_xlabel('时间 (小时)')
ax.set_ylabel('客流量')
ax.set_xlim(0, 24)
ax.set_xticks(range(25))
ax.set_xticklabels([f'{i}:00' if i % 2 == 0 else '' for i in range(25)])

# 调整图例的位置和大小
ax.legend(loc='upper left', bbox_to_anchor=(1.05, 1), borderaxespad=0., fontsize='small')

# 手动调整子图之间的间距
plt.subplots_adjust(left=0.1, right=0.8, top=0.9, bottom=0.1)

# 显示图表
plt.show()

整体来说,这些线路的早高峰时间段: 大多数站点的早高峰集中在08:00-08:30之间,特别是08:00-08:15和08:15-08:30两个时间段。 个别站点的早高峰时间较晚,如Station 76(09:45-10:00)和Station 77(09:30-09:45);我们可以看到,晚高峰的分布时刻带更宽,根据站点的分布情况和地理位置等情况,个站点晚高峰到来的时刻更早或晚,大多数站点的晚高峰集中在17:15-18:00之间,特别是17:15-17:30和17:30-17:45两个时间段;

A线路各个站点在全天的进站客流量中,早晚高峰15分钟的最大客流时刻分布情况

B线路各个站点在全天的进站客流量中,早晚高峰15分钟的最大客流时刻分布情况

C线路各个站点在全天的进站客流量中,早晚高峰15分钟的最大客流时刻分布情况

我们使用Python脚本再来探究一下地铁各线路的进站客流数据进行分析,找出各线路进站客流前10名的站点客流分布情况和特征;

完整代码#运行环境Python 3.11

python 复制代码
# -*- coding: utf-8 -*-

import pandas as pd

def read_and_process_file(file_path):
    try:
        df = pd.read_csv(file_path)
        df['time'] = pd.to_datetime(df['time'])
        return df
    except Exception as e:
        print(f"Error processing file {file_path}: {e}")
        return None

# 文件路径列表
file_paths = [
    'D:\\data\\record_2019-01-08.csv',
    'D:\\data\\record_2019-01-09.csv',
    'D:\\data\\record_2019-01-10.csv',
    'D:\\data\\record_2019-01-11.csv',
    'D:\\data\\record_2019-01-12.csv',
    'D:\\data\\record_2019-01-13.csv',
    'D:\\data\\record_2019-01-14.csv'
]

# 读取并处理所有文件
dfs = [read_and_process_file(file_path) for file_path in file_paths]
df = pd.concat(dfs, ignore_index=True)

# 过滤 A 线的数据
a_line_data = df[df['lineID'] == 'A']

# 提取进站数据
inbound_data = a_line_data[a_line_data['status'] == 1]

# 计算每天的平均进站客流
daily_inbound_flow = inbound_data.groupby([inbound_data['time'].dt.date, 'stationID'])['userID'].count().reset_index()
daily_inbound_flow.columns = ['date', 'stationID', 'inbound_count']

# 计算每个站点的平均进站客流
average_inbound_flow = daily_inbound_flow.groupby('stationID')['inbound_count'].mean().reset_index()
average_inbound_flow.columns = ['stationID', 'average_inbound_count']

# 按平均进站客流排序并取前10名
top_10_inbound_stations = average_inbound_flow.sort_values(by='average_inbound_count', ascending=False).head(10)

# 输出前10名站点的平均进站客流到 CSV 文件
output_file_path = 'D:\\data\\top_10_inbound_stations.csv'
top_10_inbound_stations.to_csv(output_file_path, index=False)
print(f"Top 10 inbound stations data saved to {output_file_path}")

我们可以看到A线路每天平均进站客流前10名站点客流呈阶梯式递减,B线路每天平均进站客流前10名站点中编码15的站点客流占大头,其他客流呈较为相似状态,差别不大,C线路每天平均进站客流前10名站点中,客流客流较为均衡,线路整体各站点进站客流较为平稳;

A线路每天平均进站客流前10名站点

B线路每天平均进站客流前10名站点

C线路每天平均进站客流前10名站点

文章仅用于分享个人学习成果与个人存档之用,分享知识,如有侵权,请联系作者进行删除。所有信息均基于作者的个人理解和经验,不代表任何官方立场或权威解读。

相关推荐
韭菜炒鸡肝天7 分钟前
VTK开发笔记(一):VTK介绍,Qt..+VSx+VTK.编译
开发语言·笔记·qt
Gu Gu Study11 分钟前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
Aaron - Wistron44 分钟前
Web API C# (Furion版)带 单元测试
开发语言·后端·c#
卷无止境1 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境1 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1231 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
江畔柳前堤1 小时前
系统的本质——从LTI系统到神经网络
人工智能·深度学习·神经网络·机器学习·计算机视觉·数据挖掘·语音识别
Dxy12393102162 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb002 小时前
一个项目带你入门AI应用开发01
python
0566462 小时前
Python康复训练——常用标准库
开发语言·python·学习