跳轉到內容

運輸部署案例集/2021/密西西比州

來自華夏公益教科書,為開放世界提供開放書籍

密西西比州有軌電車

[編輯 | 編輯原始碼]
比洛克西有軌電車,20世紀初

有軌電車(也常稱為電車、無軌電車或電力鐵路)是一種公共交通方式,它在街道上建造的鐵軌上執行。與公交車不同,有軌電車被限制在現有的鐵軌上,無法到達沒有預先存在的鐵軌的地方。此外,與其他在鐵路網路上執行的公共交通系統(特別是火車和地鐵系統)不同,有軌電車通常在街道景觀上與混合交通一起執行,並與行人和車輛共享道路,而不是在地下深處或專用鐵軌上孤立執行。雖然歷史上,有軌電車使用過各種電源,但現在最常見的是依賴電力。

技術特徵

[編輯 | 編輯原始碼]

有軌電車的設計目標是服務兩種主要目的之一:運輸貨物和運輸乘客,從一個地點到另一個地點。與其他交通方式一樣,服務使用會產生少量費用,由網路所有者收取。在美國以及世界各地,有軌電車網路通常由私營公司擁有和運營。毫無疑問,這些網路的建設目的是為了最大限度地提高公司的回報。因此,鐵軌通常建在預計使用量最大的地區,以最佳化回報。這種激勵措施通常是可取的,因為它允許網路為儘可能多的人提供可及性,從而創造健康的自然供求關係。

優點和缺點

[編輯 | 編輯原始碼]

有軌電車的主要優點和缺點[1]總結在下表中

有軌電車的優缺點
優點 缺點
服務可靠且頻繁,避免了交通擁堵 容量遠低於其他固定軌道交通服務
停車距離相對較短,可以為人口稠密地區(如中央商務區)提供良好的可達性。路線通常也比較短(不到 10 英里) 短停車距離導致速度明顯降低,因為這限制了加速到最大可能速度的能力
雖然沒有高速鐵路那麼快,但有軌電車的執行速度仍然與其他交通方式相似 不適合作為長途服務,因為車輛速度是關鍵的關注領域
有軌電車路線清晰可見,易於理解和使用 有軌電車與其他交通方式共享道路,如果交通標誌不足,可能會更加危險
由於其簡單性,有軌電車吸引了遊客和當地使用者 有軌電車的速度、車廂大小和頻率有限,因此無法提供足夠的容量作為主要交通方式
可以為高容量、高速交通方式之間提供高效可靠的連線
建設成本明顯低於其他固定軌道交通服務,如輕軌和單軌
有軌電車系統可以顯著促進其鄰近地區的經濟發展
與其他能源來源相比,使用電力減少了交通運輸對環境的影響

在有軌電車發展和廣泛使用之前,陸地乘客運輸最常見的方式是使用馬拉車輛;其中最流行的是公共馬車。這些通常由一個封閉的乘客車廂組成,車廂兩側有木質長凳。車廂由四個木製輻條車輪支撐,由一匹或兩匹馬牽引。駕駛員通常坐在車廂外的單獨的前向長凳上。從 18 世紀到 19 世紀,公共馬車在美國和歐洲都很流行。

然而,馬拉公共馬車效率低下。由於車輪與未鋪砌地面的滾動阻力,拉動馬車的力很大。拉動馬車的馬會很快疲勞,這使得公共馬車的運營時間每天只有幾個小時。即使這樣,為了使這種服務能夠按照時間表正常執行,公司必須為他們運營的每項服務飼養和照顧數十匹馬。

因此,公共馬車服務相對昂貴。在大多數城市,中下階層因此通常選擇步行作為主要的交通方式 [2]。然而,缺乏鋪路意味著步行通勤經常是泥濘的,如果不是塵土飛揚的話。道路上也通常佈滿了拉動公共馬車的馬糞。這使得通勤成為一段不愉快的旅程。因此,人們一直渴望發展公共交通,因為對更好交通方式的需求一直存在。

有軌電車的發明

[編輯 | 編輯原始碼]

有軌電車的發展和增長是幾個世紀以來積累的技術進步融合的結果。它的成功主要歸功於工業革命中鐵器加工技術的結合、電力發動機的採用以及人類將各種想法結合在一起的創造力。

雖然早在 16 世紀就已使用鐵軌,但它們最初用於從礦山中運輸大量的礦石。早期發明的鐵軌是用木頭建造的,車輪也是用木頭建造的。手推車本身是馬拉的,或者由一根纜繩拉動。然而,直到 18 世紀,才將馬拉手推車在鐵路系統上的概念引入城市內部的交通方式。這種系統透過減少手推車車輪與鐵軌之間的滾動阻力,顯著提高了行駛的平穩性,從而解決了馬匹疲勞的問題。因此,一輛更大的手推車能夠由一匹馬而不是兩匹馬拉動,就像公共馬車一樣。因此,公司能夠以更低的成本運營交通服務,同時提供更舒適的服務。

18 世紀中期,蒸汽機的發明導致了被稱為工業革命的爆炸式增長。在此期間,鼓風爐的發明極大地提高了鋼鐵產量。因此,在 18 世紀後期,開始使用鑄鐵製造鐵板和輪子。通常在木軌的上表面固定一層鑄鐵,形成複合木/鐵軌軌道。在軌道中使用鑄鐵是比使用木材更上一層樓。與木製的前身相比,它們可以承受更高的負荷,而且滾動阻力更小,從而進一步提高了效率和舒適度。然而,鑄鐵也存在相應的問題。它很脆,容易磨損。高流量和使用重負荷對軌道的持續使用會導致軌道損壞。因此,鑄鐵板需要經常更換,這也是一筆巨大的經濟開支。

19 世紀初,一種新的金屬加工工藝的發明解決了鑄鐵的脆性問題,這種工藝創造了一種被稱為熟鐵的延展性材料。這是另一個改進,因為熟鐵的延展性使軌道使用壽命更長,提高了經濟效率。然而,熟鐵的柔軟性仍然意味著軌道在需要維護、修理或更換之前,使用壽命不到 10 年。這是有軌電車網路發展的一個主要制約因素。

19 世紀中後期,貝塞麥法和露天爐相繼發明。這兩種技術的結合使鋼材能夠以非常低的成本高效地生產。在這種情況下,由於鋼軌具有理想的效能,因此迅速採用鋼軌。鋼材強度高,耐用且成本低,這意味著其使用壽命比熟鐵製成的鋼軌長得多,而且價格相似。這導致了堅固、耐用且光滑的鋼軌,在 19 世紀後期引發了鐵路行業的爆炸式增長。許多鐵路公司開始運營,在接下來的幾十年裡,數千英里的鐵路軌道被建造。

人們曾嘗試過利用不同的動力來源為有軌電車提供動力。然而,隨著時間的推移,人們發現蒸汽機體積太大,無法安裝在小型車輛上,柴油發動機則過於笨重,效率低下。因此,動力來源的選擇迅速轉向電力,因為電力體積小且效率高,尤其適合輕便的車輛,如電車。到 19 世紀初,大多數有軌電車從馬拉的馬車轉換為電氣化的鐵路。

使用電氣化的有軌電車意味著初始投資在合理範圍內。該系統可以透過建造軌道、承載電力的架空線路以及最終建造帶有電動機的車輛來建立。這導致了美國電車行業的快速發展。

誕生階段

[編輯 | 編輯原始碼]

市場發展

[編輯 | 編輯原始碼]

密西西比州有軌電車的誕生階段始於 19 世紀後期,採用馬拉的馬車在木製和鐵製複合軌道上執行。它們取代了馬拉的公共汽車 [3]。最早擁有這種系統的城市是格林維爾(1887 年)和納切茲(1886 年),由私人擁有的公司格林維爾有軌電車公司和納切茲有軌電車公司分別開發和擁有該系統 [3]。這些網路由私人擁有和維護,費用由公司自行承擔。到 1894 年,格林維爾有軌電車公司已擁有 10 萬美元的授權股本,並維護了 6 英里的軌道,擁有 15 匹馬和 9 輛馬車 [4]。另一方面,納切茲有軌電車公司也發展到類似的規模,同樣擁有 10 萬美元的授權股本,並維護了 5 英里的軌道以及 20 匹馬和 7 輛馬車 [4]。

19 世紀後期,其他幾個城市也有公司建造和維護馬車系統,但由於客流量低,這些路線被廢棄,運營這些系統的公司也被解散。這很可能是因為密西西比州是一個農村州,人口密度低,這使得有軌電車成為一項難以經營且經濟上不可行的業務。因此,缺乏對該服務的自然需求,使得公司難以在較小的城市中運營。因此,只有較大的城市,如梅里迪安、格林維爾、納切茲、傑克遜和灣港,擁有有軌電車系統。在任何時候,整個密西西比州最多隻有 13 條有軌電車線路。

在廣泛採用鋼軌和電動車設計之後,美國的有軌電車行業迅速發展。這是一個功能發現和增強的過程,許多人將新技術視為增長機會。密西西比州也是如此。然而,由於建造這種系統需要大量的資本投資,大多數地方政府沒有為建造提供資金。相反,他們將街道特許經營權授予私人公司,然後這些公司會獲得一定時間的特許經營權,通常是 20 年。因此,那些認為這是一個有利可圖的機會的人籌集了資金,並與地方政府簽訂了特許經營權。因此,新一輪鐵路公司被特許經營。

格林維爾的原始馬拉有軌電車系統於 1899 年停止運營,並在接下來的兩年時間裡開始建造新的電氣化鋼軌。新公司 Delta Light and Traction Co. 獲准特許經營,此後收購了格林維爾之前的鐵路公司,並壟斷了格林維爾的照明和有軌電車行業。這條線路取得了巨大成功,並在接下來的十年裡經歷了增長。

政策制定

[編輯 | 編輯原始碼]

與大多數其他州一樣,在有軌電車的誕生階段,管理有軌電車運營的立法是從之前的交通服務(即公共汽車和馬拉的有軌電車服務)借鑑而來。特別是,道路使用權政策與馬拉的有軌電車服務一致。這主要是由於馬拉的有軌電車和電力有軌電車之間存在相似之處。

然而,政府還出臺了更多政策,以降低其在公共基礎設施方面的維護成本。私人公司需要為特許經營協議支付的價格涉及條款的協商,並且經常要求私人公司為擴充套件和改善公共道路的質量做出貢獻 [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

程式碼 - 刮取資料

[編輯 | 編輯原始碼]

當資料文字檔案可用時,執行以下程式碼以簡化資料提取過程。這並不完美,因此,在提取資料後,需要一些手動工作來清理和檢查資料。

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] 蒙羅·多德。精彩之旅 - 堪薩斯城的有軌電車 1870 - 1957 年。堪薩斯城之星圖書。2002 年。

[3] 弗蘭克·A·布魯克斯二世。關於有軌電車的軼事 - 南方牽引 - 密西西比州的有軌電車旅行。1983 年。

[4] 麥格勞電氣鐵路手冊 - 美國有軌電車投資紅皮書。1894 年。

[5] 彼得·斯皮裡特。為什麼墨爾本保留了它的電車。城市和規劃史的景觀和生態。

華夏公益教科書