跳转到内容

运输部署案例集/2021/密西西比州

来自维基教科书,为开放世界提供开放书籍

密西西比州有轨电车

[编辑 | 编辑源代码]
比洛克西有轨电车,20世纪初

有轨电车(也常被称为电车、拖车或电气铁路)是一种公共交通工具,在街道上建造的轨道上运行。与公共汽车不同,有轨电车被限制在现有的轨道上,无法到达没有预先存在的轨道的区域。此外,与其他在铁路网络上运行的公共交通系统(尤其是火车和地铁系统)不同,有轨电车通常在街道景观上与混合交通一起运行,并与行人和车辆(偶尔)共享道路,而不是在深地下或专用轨道上单独运行。历史上,有轨电车已在各种电源上运行,但现在最常依靠电力。

技术特点

[编辑 | 编辑源代码]

有轨电车的设计目的是为了服务于两种主要目的之一:运输货物和运输乘客,从一个地点到另一个地点。与其他运输方式一样,使用该服务需要用户支付少量费用,并支付给网络所有者。在美国以及世界各地,有轨电车网络通常由私人公司拥有和运营。毫无疑问,这些网络的建设目的是为了将公司的收益最大化。因此,轨道通常建在预计使用量最大的区域,以优化回报。这种激励措施通常是可取的,因为它允许网络为尽可能多的人提供可达性,从而创造健康的自然供求关系。

优点和缺点

[编辑 | 编辑源代码]

有轨电车的主要优点和缺点 [1] 总结在下表中

有轨电车的优点和缺点
优点 缺点
服务可靠且频繁,避免了拥挤和交通繁忙区域的交通拥堵 容量远低于其他固定轨道交通服务
停车距离相对较短,可以通过密集区域(如中央商务区)提供良好的可达性。路线通常也很短(不到 10 英里) 短停车距离导致速度明显降低,因为它限制了加速到最大可能速度的能力
虽然不如高速铁路快,但有轨电车的运行速度仍然与其他交通方式类似 不适合作为长途服务,因为车辆速度是关键的关注领域
有轨电车路线清晰可见、易于理解且可达 有轨电车与其他交通方式共享路权,如果交通标志不足,可能会更危险
有轨电车因其简单性而吸引了游客和当地用户 有轨电车受速度、车厢大小和频率限制,因此无法提供足够的容量作为主要交通方式
可以为容量更大、速度更高的交通方式提供高效可靠的连接
建筑成本明显低于其他固定轨道交通服务,如轻轨和单轨
有轨电车系统可以为其周边社区的经济发展做出重大贡献
使用电力而不是其他能源来源,减少了交通对环境的影响

在有轨电车发展和广泛使用之前,陆地乘客运输最常见的方式是通过马拉车厢进行的;其中最流行的是公共汽车。这些通常包括一个封闭的乘客舱,两侧有木制长凳。驾驶室由四个木制辐条轮支撑,由一匹或两匹马拉着。司机通常坐在驾驶室外的独立的前向长凳上。公共汽车在美国和欧洲在 18 世纪到 19 世纪都很流行。

但是,马拉公共汽车效率低下。由于车轮与未铺砌地面之间的滚动阻力,拉动马车所需的力很大。拉动马车的马匹会很快疲劳,限制了公共汽车每天的运行时间。即使这样,为了使这样的服务能够按照时间表正常运营,公司必须为其运营的每项服务提供和照顾数十匹马。

因此,公共汽车服务相对昂贵。在大多数城市,中下层阶级因此经常选择步行作为主要交通方式 [2]。然而,缺乏铺砌意味着步行通勤通常泥泞不堪,如果不是尘土飞扬的话。道路上也经常布满马匹拉动公共汽车留下的粪便。这使得通勤成为一次不愉快的旅程。因此,对公共交通增长的兴趣一直存在,因为对更好交通工具的需求一直存在。

有轨电车的发明

[编辑 | 编辑源代码]

有轨电车的发展和增长是几个世纪以来积累的各种技术进步的融合的结果。它的成功主要归功于工业革命的钢铁加工技术、电力发动机的采用以及人类将各种想法结合起来的独创性。

尽管铁路的历史可以追溯到十六世纪,但最初它们被用来从矿山运送大量的矿石。早期发明的铁路轨道是用木材建造的,就像手推车的轮子一样。手推车本身是用马拉或用缆绳拉动。然而,直到十八世纪,马拉马车在铁路系统上的概念才作为城市内部的一种交通方式被引入。这种系统通过减少手推车车轮与轨道之间的滚动阻力,显着提高了行驶的平稳性,解决了马匹疲劳的问题。因此,一辆更大的马车可以用一匹马而不是两匹马来拉,就像公共汽车一样。因此,公司能够以更低的成本运营运输服务,同时提供更舒适的服务。

在十八世纪中叶,蒸汽机的发明导致了被称为工业革命的爆炸性增长。在此期间,鼓风炉的发明显着提高了钢铁产量。因此,在十八世纪后期,铁板和车轮开始使用铸铁制成。通常将一层铸铁固定在木制轨道的上表面,形成复合木/铁轨道。在轨道中使用铸铁是比使用木材的一大进步。它们可以承受明显更高的载荷,并且与木制的前身相比,滚动阻力更小,进一步提高了效率和舒适性。然而,铸铁也有其对应的一系列问题。它很脆,容易磨损。高流量和对轨道持续使用重载荷会导致轨道损坏。因此,铸铁板需要经常更换,这也使其成为一项重大的经济开支。

在十九世纪初期,一种新的金属加工工艺的发明解决了铸铁的脆性问题,这种工艺创造了一种称为锻铁的延展性材料。这是一项改进,因为锻铁的延展性使轨道可以持续更长时间,使其更具经济效益。然而,锻铁的柔软性仍然意味着轨道在需要维护、修理或更换之前只能持续不到 10 年。这是限制有轨电车网络增长的一个关键因素。

在十九世纪中后期,贝塞麦法和露天炉被发明出来。这两种方法的结合使钢材能够以非常低的成本高效生产。在这种情况下,由钢材制成的铁路轨道被迅速采用,因为其具有理想的特性。钢材的高强度以及其耐用性和低成本意味着它的使用寿命远远超过由锻铁制成的轨道,而且价格也相当。这带来了坚固、持久且平滑的轨道,在十九世纪后期引发了铁路行业的爆炸性增长。许多铁路公司开始运营,并在接下来的几十年里修建了数千英里的铁路轨道。

人们曾尝试过使用不同的动力来源来驱动有轨电车。然而,随着时间的推移,人们发现蒸汽机体积太大,无法装入小型车辆,而柴油发动机又太重,因此效率低下。因此,首选的动力来源迅速转向电力,因为它体积小,效率高,特别适用于有轨电车等轻型马车。到十九世纪初,大多数有轨电车系统已从马匹牵引的马车转换为电力驱动铁路。

使用电力有轨电车意味着最初的投资是合理的。该系统可以通过修建铁路轨道、输送电力的架空线路以及最后修建车厢(车厢上装有电动机)来建立。这导致美国有轨电车行业迅速扩张。

孕育阶段

[edit | edit source]

市场发展

[edit | edit source]

密西西比州有轨电车的孕育阶段始于十九世纪后期采用马拉马车沿着木制和铁制复合轨道运行。这些马车取代了马拉公共汽车 [3]。最早使用这种系统的城市是格林维尔 (1887) 和纳奇兹 (1886),私营公司格林维尔有轨电车公司和纳奇兹有轨电车公司分别是该系统的开发商和所有者 [3]。这些网络由私人拥有和维护,由公司自行承担费用。到 1894 年,格林维尔有轨电车公司拥有 100,000 美元的授权股本,并维护着 6 英里的轨道,配备 15 匹马和 9 辆马车 [4]。另一方面,纳奇兹有轨电车公司也发展到类似的规模,也拥有 100,000 美元的授权股本,并维护着 5 英里的轨道,以及 20 匹马和 7 辆马车 [4]。

十九世纪后期,其他几个城市也有公司建造和维护马车系统,但由于客流量低,这些路线被废弃,运营这些系统的公司也解散了。这可能是因为密西西比州是一个农村州,人口密度低,这使得有轨电车成为一项难以盈利且不可行的业务。因此,缺乏对服务的自然需求使得公司难以在较小的城市运营。因此,只有较大的城市,如梅里迪安、格林维尔、纳奇兹、杰克逊和格尔夫波特才有有轨电车系统。在任何时候,整个密西西比州最多只有 13 条有轨电车线路。

在钢铁轨道和电动车设计广泛采用后,全美有轨电车行业迅速发展。这是一个功能发现和改进的过程,许多人将这项新技术视为发展的机会。密西西比州也是如此。然而,由于修建这些系统需要大量的资本投资,大多数地方政府并没有为其建设提供资金。相反,他们将街道特许经营权授予私营公司,这些公司随后将被特许经营一段时间,通常为 20 年。因此,那些将此视为盈利机会的人募集资金,并与地方政府组建了特许经营权。结果,新一轮的铁路公司被特许成立。

格林维尔最初的马拉有轨电车系统于 1899 年停运,并在两年内开始修建新的电力钢轨。新公司三角洲电力和牵引公司获得特许经营权,随后收购了格林维尔之前的铁路公司,垄断了格林维尔的照明和有轨电车行业。这条线路取得了巨大成功,并在接下来的十年里不断发展。

政策制定

[edit | edit source]

与大多数其他州一样,管理有轨电车运营的法律是在孕育阶段从之前的交通服务中借鉴来的,即公共汽车和马拉有轨电车服务。特别是,道路通行权政策与马拉有轨电车服务的政策一致。这主要是由于马拉有轨电车和电力驱动有轨电车之间的相似性。

然而,政府进一步推出了更多政策来降低其公共基础设施维护成本。私营公司需要为特许经营协议支付的价格涉及条款谈判,并且通常要求私营公司为公共道路的扩建和质量提升做出贡献 [2]。虽然私营公司经常反对这些政策,但最终在签署特许经营协议后,他们还是在勉强的同意下接受了这些政策。

与格林维尔类似的市场增长模式也出现在密西西比州的其他主要有轨电车城市,包括梅里迪安、纳奇兹和杰克逊,在这些城市,建造、维护和运营有轨电车系统的公司应运而生。很快,每个城市都有自己相应的私营公司,这些公司采用了一种模式,即同时运营照明和电力有轨电车服务。这些私营公司规模相对较小,并且由于对更多服务的需求有限,并没有扩展到城市以外。这些公司的规模较小,导致服务管理简单直接,总体上形成了一个短暂但成功的有轨电车系统 [4]。

然而,有轨电车系统在整个城市的缺乏竞争和垄断自然会导致票价上涨。因此,随着系统的成熟,政府在特许经营协议中引入了锁定政策,以防止运营商将票价提高到 5 美分以上。所有已同意特许经营权的运营商因此需要将票价保持在 5 美分,无论市场情况如何。结果,有轨电车系统受到公众的欢迎,新服务的开通往往伴随着热烈的庆祝活动 [3]。

增长阶段

[编辑 | 编辑源代码]

公共部门贡献

[编辑 | 编辑源代码]

虽然当时有轨电车系统的增长规模小于美国其他城市,因为密西西比州的需求较小,但政府在发展中仍然发挥着关键作用。特别是,政府通过特许经营协议主要控制着系统的规划。通过将有轨电车的路线限制在特定路线,政府控制着服务的城市规划部分。此外,通过推出上述政策,例如服务上的最高票价,政府能够确保服务能够轻松地被大众使用。因此,这种规划指引着更有效率的经济增长道路。

私营部门贡献

[编辑 | 编辑源代码]

私营部门是有轨电车服务的主要贡献者。私营公司负责建设、拥有、维护和运营所有系统,并期望从服务中获利。虽然他们必须按照特许经营协议中商定的政策运营,但私营公司一直在寻求提高效率和最大化利润。这促使私营公司将有轨电车服务扩展到私营公司认为有利可图的地区,也为私营公司创造了提高服务质量以增加乘客数量的动力。因此,铁路公司会购买照明公司,并在沿线提供照明服务以吸引乘客。因此,私营部门为公共交通网络基础设施、服务的运营以及城市基础设施质量的改善做出了巨大贡献。

政策问题

[编辑 | 编辑源代码]

公共部门和私营部门之间最大的利益冲突在于与票价相关的政策。管理机构希望低成本易于使用,而私营公司则希望最大化利润。虽然锁定政策最初并没有问题,该政策限制了有轨电车运营商可以收取的票价,但在 20 世纪通货膨胀开始发生时,它就成为问题了。结果,许多铁路公司不再具有经济可行性,很快就被汽车等其他交通工具所取代。

成熟阶段

[编辑 | 编辑源代码]

由于密西西比州人口密度低,有轨电车网络的成熟阶段较早到来,大约在 1918 年左右。大多数有轨电车系统没有经历显著增长,乘客数量多年来没有改善。因此,私营公司没有继续扩展网络的动力,因为这样做不会有利可图。

这进一步加剧了 5 美分最高票价的锁定政策。随着通货膨胀的加剧,乘客数量没有改善意味着私营部门的利润逐渐下降,最终它们不再具有经济可行性。福特汽车公司对汽车的精简生产是推动有轨电车行业进入衰退阶段的最终因素。到 1930 年,汽车行业发展迅速,有轨电车系统被更有效率、更灵活且不需要广泛铁路基础设施的公共汽车迅速取代 [5]。由于路权政策自马车时代以来没有改变,有轨电车需要与道路上的其他车辆共用道路。因此,其他交通工具(包括汽车和公共汽车)的增加使得争夺路权,并由于有轨电车的缺乏灵活性而使其退出了服务。因此,在 1930 年代到 1950 年代之间,超过一百个城市放弃了有轨电车系统,并将其替换为公共汽车和私人汽车 [5]。密西西比州的所有城市都属于放弃有轨电车系统的城市类别。到 1930 年代中期,密西西比州不再有任何有轨电车 [3]。

重新设计交通方式

[编辑 | 编辑源代码]

虽然有轨电车早已被废弃,并被公共汽车等更灵活的服务所取代,但有轨电车仍然具有一系列优势。因此,存在着将有轨电车重新设计用于现代用途的机会,特别是在交通拥堵的地区使用短轨。但是,必须相应地改变政策以适应这种情况。中心商务区的交通拥堵道路可以轻松地低成本地转换为有轨电车系统。但是,为了防止进一步的路权冲突,有必要改造道路,以便汽车、公共汽车和有轨电车之间没有冲突。

有轨电车系统也不太可能对私营部门有利可图。因此,公共部门的资金对于重新设计这样的系统也是必要的。虽然资本成本相对较高,但与有轨电车相关的经济效益和增长可能超过线路的成本。

定量分析

[编辑 | 编辑源代码]

对于密西西比州每一个拥有有轨电车系统的城市,都进行了定量分析,将密西西比州有轨电车系统的轨道长度拟合到逻辑函数,以识别三个发展阶段:诞生阶段、增长阶段和成熟阶段。数据是从“McGraw 电气铁路手册 - 美国有轨电车投资红皮书”收集的,时间范围为 1894 年至 1920 年,尽可能使用自动化的 Python 脚本。然后手动检查数据,并将其用于曲线拟合。用于拟合数据的函数是

其中 表示 年的轨道长度(英里), 表示系统成熟阶段的饱和轨道长度,以及 是使用线性形式的最小二乘回归拟合的参数

由于某些网络尚未进入成熟阶段,参数 未知。在这种情况下,我们迭代遍历一系列可能的数值,并最大化最小二乘回归中的相关性 。此优化问题使用 Python 中的暴力迭代法求解。对于研究期间密西西比州的每个系统,都拟合了逻辑函数,尽管一些数据表明逻辑函数可能不是最佳拟合函数。

密西西比州 - 汇总

[编辑 | 编辑源代码]

将密西西比州所有系统的数据汇总在一起,以查找 1894 年至 1920 年间密西西比州的总轨道长度。当没有关于系统轨道长度变化的报告时,假设轨道没有发生变化,因此保持了其之前报告的长度。下表总结了每年的结果。

密西西比州有轨电车轨道长度的逻辑回归。
年份
1894 26.50 16.18
1895 26.50 18.68
1896 26.50 21.51
1897 23.50 24.67
1898 21.50 28.19
1899 28.00 32.07
1900 29.00 36.30
1901 32.00 40.87
1902 28.50 45.76
1903 36.00 50.92
1904 56.70 56.31
1905 49.75 61.86
1906 58.30 67.50
1907 82.30 73.16
1908 95.30 78.76
1909 95.70 84.22
1910 98.90 89.49
1911 106.40 94.49
1912 107.90 99.20
1913 106.40 103.58
1914 104.20 107.60
1915 104.20 111.27
1916 104.20 114.58
1917 123.51 117.54
1918 123.51 120.18
1919 123.51 122.51
1920 117.73 124.56

下表总结了逻辑回归的系数

137.4 0.16 1906.2 0.927

从逻辑回归中,其中 被优化,似乎逻辑函数似乎是数据的一个合理的拟合函数。该 值在 0.927 处相当高,这表明此曲线的拟合优度非常高。但是,话虽如此,记录数据和拟合线之间似乎仍然存在一些差异。在优化拟合优度后,发现密西西比州轨道饱和长度约为 137.4 英里。因此,在研究期之外的几年里,仍然有增长空间。出生阶段的大致年份为 1882 年至 1898 年,增长阶段为 1898 年至 1917 年,成熟阶段为 1917 年至 1930 年,此后不久便开始下降。

为了完整起见,还对密西西比州每个城市进行了逻辑回归分析。但是,一些城市,如纳奇兹,表明逻辑函数可能不是最佳拟合模型。然而,格林维尔、杰克逊和梅里迪安等其他城市表明逻辑函数是一个合理的拟合,因为拟合优度相对较高。

哥伦布

[编辑 | 编辑源代码]
哥伦布,密西西比州有轨电车轨道长度的逻辑回归。

哥伦布似乎很早就经历了出生阶段,在 1906 年之前。然而,直到 1906 年,增长才迅速扩展,并在 1910 年迅速达到成熟和饱和阶段。

年份
1907 4.50 3.84
1908 5.60 5.40
1909 6.70 6.25
1910 6.70 6.61
1911 6.70 6.73
1914 5.00 6.80
1917 6.80 6.80
1918 6.80 6.80

格林维尔

[编辑 | 编辑源代码]
格林维尔,密西西比州有轨电车轨道长度的逻辑回归。

格林维尔最初使用的是马拉有轨电车系统。然而,在引入电力有轨电车后,原始系统被废除,轨道线路被电气化。因此,电力有轨电车系统的出生阶段始于 1901 年左右,随后从 1904 年到 1911 年快速扩展,此后网络在约 7.75 英里长时饱和。

年份
1899 0.00 0.00
1900 0.00 0.00
1901 0.00 0.00
1902 2.00 0.00
1903 2.00 0.01
1904 2.00 0.04
1905 2.00 0.15
1906 4.30 0.53
1907 4.80 1.61
1908 5.00 3.78
1909 5.00 6.01
1910 5.00 7.17
1911 7.00 7.58
1914 7.00 7.75
1917 7.75 7.75
1918 7.75 7.75
1920 7.75 7.75
湾港,密西西比州有轨电车轨道长度的逻辑回归。

湾港似乎也经历了从 1905 年出生到 1906 年至 1910 年增长阶段的快速扩张。湾港网络规模大于密西西比州的大多数其他城市,并在 1911 年左右达到 30 英里的饱和状态。

年份
1905 1.75 9.75
1906 8.00 18.99
1907 23.00 25.82
1908 25.00 28.70
1909 25.00 29.63
1910 25.00 29.89
1911 30.00 29.97
1912 30.00 29.99
1913 30.00 30.00
1914 30.00 30.00
1917 30.00 30.00
1918 30.00 30.00
1920 30.00 30.00

杰克逊

[编辑 | 编辑源代码]
杰克逊,密西西比州有轨电车轨道长度的逻辑回归。

杰克逊似乎也相当适合逻辑函数。出生阶段始于 1893 年左右,并迅速从 1900 年左右进入增长阶段,一直持续到 1910 年,此后网络逐渐成熟。虽然数据仅限于 1920 年之前,但逻辑函数表明,网络继续成熟,直到达到 15.6 英里的潜在饱和长度。

年份
1894 1.50 1.87
1897 1.50 3.00
1898 1.50 3.47
1899 6.00 4.00
1900 6.00 4.58
1901 6.00 5.20
1902 6.00 5.86
1903 8.00 6.55
1904 5.20 7.27
1905 5.50 7.99
1906 5.50 8.71
1907 14.00 9.41
1908 12.00 10.09
1909 12.00 10.73
1910 12.00 11.32
1911 12.50 11.87
1912 14.00 12.37
1913 12.50 12.82
1914 14.00 13.21
1917 13.50 14.13
1918 13.50 14.35
1920 13.50 14.71

梅里迪安

[编辑 | 编辑源代码]
密西西比州梅里迪安有轨电车轨道长度的逻辑回归。

梅里迪安的逻辑函数拟合度很高。该网络在 1890 年左右就出现了,并在 1894 年至 1910 年的增长阶段,轨道长度扩展到约 11 英里。随后,该网络进入成熟阶段,最终在约 14 英里的长度上饱和。

年份
1898 6.00 4.65
1899 6.00 5.16
1900 6.00 5.70
1901 6.00 6.25
1902 6.00 6.81
1903 6.00 7.38
1904 7.50 7.94
1905 7.50 8.48
1906 7.50 9.01
1907 9.00 9.52
1908 11.00 10.00
1909 11.50 10.44
1910 11.50 10.85
1911 11.50 11.23
1912 11.50 11.57
1913 11.50 11.88
1914 11.50 12.16
1917 13.12 12.81
1918 13.12 12.97
1920 13.12 13.24

纳奇兹

[编辑 | 编辑源代码]
密西西比州纳奇兹有轨电车轨道长度的逻辑回归。

纳奇兹是一个有趣的案例,它并不十分适合逻辑函数。拟合度很差,拟合参数也不能很好地反映网络发展的三个阶段。但是,可以肯定地说,该网络在很早的时候就成熟了,并且保持在 7 英里的饱和长度。

年份
1897 6.00 6.81
1898 6.00 6.90
1899 6.00 6.94
1900 6.00 6.97
1901 4.00 6.98
1902 3.50 6.99
1903 7.00 6.99
1904 7.00 7.00
1905 7.00 7.00
1906 7.00 7.00
1907 7.00 7.00
1908 7.00 7.00
1909 7.00 7.00
1910 7.00 7.00
1911 7.00 7.00
1912 7.00 7.00
1913 7.00 7.00
1914 6.00 7.00
1917 7.00 7.00
1918 7.00 7.00

代码 - 抓取数据

[编辑 | 编辑源代码]

当数据可用为 txt 文件时,运行以下代码可以简化数据提取过程。这并不完美,因此在提取数据后,需要进行一些手动操作来清理和检查数据。

import pandas as pd
import re
import us
import matplotlib.pyplot as plt

def read_file(year):
    out = None
    with open(
        f'McGraw electric railway manual - the red book of American street railway investment - {year}.txt',
        encoding="utf8"
    ) as f:
        out = pd.DataFrame(f)
        out['Year'] = year
        out[0] = out[0].apply(lambda x: x.strip())
    return out
    
final_data = None

regex_exp = re.compile(
    '.*(Miles[,]?[\ ]?of track|Miles[\ ]?of tracfc|Miles[\ ]?of tyack)' + # 1
    '([\ ]?\(?\S*\)?)?' + # 2
    '[,|\.]?' + 
    '(\ \(.*\)' + # 3
    '[,|\.]?)?' + 
    '[\ |\.]' + 
    '([0-9]*)' + # 4
    '\.?' + 
    '([0-9]*).*' # 5
)

for year in [1894, 1898, 1899, 1900, 1901, 1902]:
    df = read_file(year)

    companies = list(df.iloc[df[
        (df[0].str.lower().str.contains('co[\.]?[\ ]?—|co.$'))
    ].index][0])



    def get_company(x):
        if x in companies:
            return x
        else:
            return pd.np.nan

    df['Company'] = df[0].apply(get_company)
    df['Company'] = df['Company'].ffill()

    headings = df[
        (df[0].str.isupper() | df[0].str.islower()) &
        (df[0].str.contains('.*[,|\.].*\.$'))
    ].copy()

    next_heading = list(headings.index)
    next_heading.pop(0)
    next_heading.append(0)
    headings['Next'] = next_heading

    interest = headings[
        (headings[0].str.contains('MISS\.|HISS\.'))
    ]

    cities = []
    miles = []
    years = []
    companies = []

    for i, row in interest.iterrows(): # Iterate through all areas in the state
        strip_non_alpha = re.compile('[^a-zA-Z,\ ]')
        city = strip_non_alpha.sub('', row[0].strip().replace('\t', ' ')).strip().replace(',', '')
        query = df.iloc[i: row['Next'] + 1]
        sub_query = query[
            query[0].str.contains('Miles[,]? of t')
        ]

        if len(sub_query) == 0:
            cities.append(city)
            miles.append(-1)
            years.append(year)
            companies.append('Unknown')
            
            print(year, city)
            display(query)

        for i, data in sub_query.iterrows(): # Iterate through all the companies in the area
            try:
                mile = float('.'.join(regex_exp.match(data[0].replace('S', '5')).group(4, 5)))
            except:
                print(data[0])
            
            company = data['Company'].split('—')[0].strip()
            if len(company) > 50:
                company = company.split('.')[-2] + '.'
                
            cities.append(city.split(' ')[0])
            miles.append(mile)
            years.append(year)
            companies.append(company)

    result = pd.DataFrame({
        'year' : years,
        'city': cities,
        'miles' : miles,
        'company' : companies
    })
    
    if final_data is None:
        final_data = result
    else:
        try:
            final_data = final_data.append(result).reset_index(inplace=False, drop=True)
        except:
            display(result)
            
states = [str(i).upper() + '.' for i in us.states.STATES]

for year in range(1903, 1915):
    df = read_file(year)
    companies_list = list(df.iloc[df[
        (df[0].str.lower().str.contains('capital stock')) &
        (df[0].str.lower().str.contains('authorized'))
    ].index - 1][0])

    def get_company(x):
        if x in companies_list:
            return x
        else:
            return pd.np.nan

    df['Company'] = df[0].apply(get_company)
    df['Company'] = df['Company'].ffill()

    def get_state(x):
        if x in states:
            return x
        else:
            return pd.np.nan

    df['State'] = df[0].apply(get_state).ffill().fillna('')

    headings = df[
        (df[0].str.isupper()) &
        (df[0].str.contains('^[A-Z\ ]*\.$')) &
        (~df[0].isin(states)) &
        (
            (~df[0].str.contains('STATISTICS')) &
            (~df[0].str.contains('LIABILITIES')) &
            (~df[0].str.contains('ASSETS'))
        )
    ].copy()

    next_heading = list(headings.index)
    next_heading.pop(0)
    next_heading.append(0)
    headings['Next'] = next_heading

    interest = headings[
        (headings['State'].str.contains('MISSISSIPPI'))
    ]

    cities = []
    miles = []
    years = []
    companies = []

    for i, row in interest.iterrows(): # Iterate through all areas in the state
        strip_non_alpha = re.compile('[^a-zA-Z,\ ]')
        city = strip_non_alpha.sub('', row[0].strip().replace('\t', ' ')).strip().replace(',', '')
        query = df.iloc[i: row['Next'] + 1]
        
        sub_query = query[
            query[0].str.contains('Miles[\ ]?of')
        ]

        if len(sub_query) == 0:
            cities.append(city)
            miles.append(0)
            years.append(year)
            companies.append('Unknown')

            print(year, city)
            display(query)

        for i, data in sub_query.iterrows(): # Iterate through all the companies in the area
            try:
                mile = float(('.'.join(regex_exp.match(data[0].replace('S', '5').replace(' and ', '/')).group(4, 5))))
            except:
                print(city)
                print(year)
                print(data[0])
                mile = -1
                
            company = data['Company'].split('—')[0].strip()
            if len(company) > 50:
                company = company.split('.')[-2] + '.'

            cities.append(city)
            miles.append(mile)
            years.append(year)
            companies.append(company)

    result = pd.DataFrame({
        'year' : years,
        'city': cities,
        'miles' : miles,
        'company': companies
    })

    if final_data is None:
        final_data = result
    else:
        try:
            final_data = final_data.append(result).reset_index(inplace=False, drop=True)
        except:
            display(result)

代码 - 优化线性回归和绘图

[编辑 | 编辑源代码]
import numpy as np
import pandas as pd
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator)

df = pd.read_csv('data.csv')
mindex = []
for city in df['City'].unique():
    for year in range(df['Year'].min(), df['Year'].max() + 1):
        mindex.append((year, city))
df = df.groupby(['Year', 'City'], as_index=True).agg({
    'Miles' : 'sum'
})
df = df.reindex(mindex).unstack()

def autofit(S, plot=True, major_y=30, major_x=4, minor_y=15, minor_x=2, city=''):
    best_R2 = -1
    fit = None
    best_S_max = None
    
    for r in np.linspace(1 + 1e-6, 5, 1000):
        S_max = S.max() * r
        Y = np.log((S + 1e-6)/(S_max - S))
        R2 = np.corrcoef(Y.index, Y)[0][1]**2
        if R2 > best_R2:
            best_R2 = R2
            best_S_max = S_max
            b, bt0 = np.polyfit(Y.index, Y, deg=1)
            t0 = - bt0 / b
    
    S_t_fit = lambda t: best_S_max / (1 + np.exp(-b * (t - t0)))
    
    if plot:
        X = np.linspace(min(Y.index), max(Y.index), 100)
        S_fitted = S_t_fit(X)
        fig, ax = plt.subplots(figsize=(15, 8))
        ax.scatter(S.index, S, label='Recorded data')
        ax.plot(
            X, S_fitted, 
            label=f'$S(t) = \\dfrac{{{best_S_max:.1f}}}{{1 + \exp(-{b:.2f}(t - {t0:.1f}))}}$', 
            linestyle='--', color='r'
        )
        
        ax.set_ylabel(f'Total Track Length in {city.capitalize()} (Miles)')
        ax.set_xlabel('Year')
        ax.legend(loc='best', bbox_to_anchor=(0.5, 0., 0.4, 0.5))
        ax.set_title(f'A logistic function regression of the total track length across {city.capitalize()}')
        ax.xaxis.set_major_locator(MultipleLocator(major_x))
        ax.xaxis.set_minor_locator(MultipleLocator(minor_x))
        ax.yaxis.set_major_locator(MultipleLocator(major_y))
        ax.yaxis.set_minor_locator(MultipleLocator(minor_y))
        ax.grid(b=True, which='major', color='lightgray', linestyle='-')
        ax.grid(b=True, which='minor', color='lightgray', linestyle='--')
        
        ax.annotate(f'$R^2 = {best_R2:.3f}$', (min(X) + minor_x, min(S_fitted) + minor_y))
    
    out = pd.DataFrame({
        'S': S,
        'S_fit': S_t_fit(np.array(S.index)) 
    })
    return out

参考文献

[编辑 | 编辑源代码]

[1] Parsons Brinckerhoff. 西雅图有轨电车网络和可行性分析。西雅图交通部。2004 年

[2] Monroe Dodd. 一次辉煌的旅程 - 堪萨斯城有轨电车 1870-1957 年。堪萨斯城星报书籍。2002 年。

[3] Frank A. Brooks Jr. 关于有轨电车的轶事 - 南方牵引 - 在密西西比州乘坐有轨电车。1983 年。

[4] 麦格劳电力铁路手册 - 美国有轨电车投资红皮书。1894 年。

[5] Peter Spearritt. 为什么墨尔本保留了它的有轨电车。城市和规划历史的景观和生态。

华夏公益教科书