天天看點

使用MaxCompute進行紐約的士拼車分析前言技術方案資料分析引用

最近幾年以來出現的共享的士(uber,lyft,滴滴)給人們的出行帶來了極大的便利。随着燒錢大戰的結束,中美市場大局已定,為了維持高估值(uber 80 billion $, 滴滴30 billion $),縮減虧損,增長淨利潤,繼而進入上市流程,幾大公司都開始發掘盈利的規則。帶來的影響是,共享出行的使用者們發現:1)車越來越難打,價錢越來越高;2)使用拼車會大幅度增長時間損耗,而帶來的金錢節約卻并不明顯;3)司機發現盈利有限,真正願意開車的司機越來越少,某拼車公司正在慢慢的轉變成為一個的士資訊服務平台。這與其做成讓使用者通過手機便捷,實惠出行的願景大相徑庭。

我想說一個故事,作為這篇文章所要解決的的一個問題的引子。那天天氣炎熱,我正在公交等去高鐵站的公共汽車,由于太熱,我決定打一輛車,當我攔下來一輛車後跟司機說15塊錢到車站,司機答應了。而此時跟我同時等公交的另外一個陌生人也過來問我們要到哪裡去,當他得知目的地是火車站以後,表示也想搭車,這時候司機坐地起價要他加10塊錢。這位陌生人想想覺得可以,就加了10塊錢給他。設想一下,如果我在攔的士之前就知道這個陌生人也想去火車站,兩人決定一起打車最後的價錢是怎樣的結果?也許15-20塊錢就可以搞定問題,而不是最終的25塊。而事實上,如果大家都具有這樣的能力,我想對的士司機來說也可以增長盈利,因為更多的打車需求會讓他們的單數變多進而增加總的流水。

回到某拼車公司的話題,目前假設從阿裡巴巴西溪總部出發到杭州東站(路徑a),一個人打車的費用是100,那麼第二個人拼車也是到杭州東站附近(路徑b),這時候他可能需要付的價錢是90塊錢,也就是說總價190塊錢。大家是否認為司機會拿到這部分的差額呢?事實上,的士司機隻拿到了他們共享路程的費用((a /union b)* 20%),而不是((a + b) * 20%),如果a和b完全相等的話,那麼司機基本上不會拿到更多的錢,這部分多出來的利潤就被某拼車公司完全拿去了。 為什麼某拼車公司會這麼做而且敢這麼做呢?因為他們不但壟斷了共享車的平台,也壟斷了資訊分享的平台,一個人在上車之前他是不知道另外一個人跟在類似的時間段去類似的地方的。如若這兩個人在上車前就已經知道了對方的目的地,并聯合起來打一輛車的話,那麼這個博弈的格局就完全不同了。我們寫此文的目的就是要分析真實世界中這樣的需求是否真實存在,值不值得我們投入精力去開發或者利用一個已有的資訊平台讓有類似出行需求的人在按下打車”的按鈕前就找到對方,進而增加議價的權利。

本文使用的資料來自于todd scheider維護的紐約的士資料[1],在此文中隻分析yellow cab的資料,因為其時間跨度較長(2009-2016),同時覆寫紐約市區的範圍也更廣(所有紐約5個大區)。使用的阿裡雲大資料的技術有:maxcompute的tunnel,sql,udf,mapreduce,graph和quick bi。實驗機為阿裡雲的ecs最低配的機器。所有開發實驗工作均在公有雲上進行。本文的結構如下:第二節将介紹資料分析的技術細節,第三節為實驗結果分析。

首先我們将csv格式的資料使用tunnel導入到odps表中,使用的表的schema如下:

我們需要給每一個事件指定一個唯一的id,用于後續的圖分析,唯一id的指定我們可以引用用[2]中的技術,但是當資料量比較大時,這個方法無法保證id的唯一性,經過一系列調研後,發現這個id生成在odps中是一個比較難的問題,是以我選擇在tunnel導入之前就計算好每個記錄的id,使用的tunnel導入的script如下:

計算vid的python代碼如下:

這樣我們得到的資料一共有:866,796,462條資料。       

首先我們要建立一張表來存儲需要被計算的内容:

并且将資料注入:

我們使用一個點(vertex)來表示一個打車事件,假設兩個打車事件之間的起始時間在100秒内,起始距離在200米内,終點距離在500米内,我們認為這兩個打車事件具備拼車的可能性(這個标準可以調整,但是我認為這個标準已經比較嚴格)。那麼我們用一條邊(edge)将這兩個點連接配接起來,将所有可能拼車的點用邊相連,我們便得到了一個圖(graph)。圖的schema如下所示:

生成圖和進行資料清理我們使用mapreduce來進行,mapper和reducer的代碼如下顯示:

mapper做的事情很簡單,就是生成一個以小時為機關的key,進行資料清洗(坐标值不能為0)同時将時間轉換成為time stamp。

reducer則負責将本key内的所有資料進行距離計算(起始時間,起始位置,終點位置),并輸出可連接配接的點。這裡面為了提升效率,我們将資料按照時間進行排序,超過時間範圍的則不計算,事實上可以提升效率的方法有很多種,比如說使用r-tree等等 [3]。将代碼打包并進行計算的odps指令如下(注意這段代碼是可以指定執行的mapper reducer個數的):

經過計算,一共有497,819,232個點和1,373,388,220條邊,也就是說有這麼多個打車事件與其它事件有拼車可能性。

當兩人拼車時,我們使用邊即可以表達這個關系,三人拼車時三角形可以進行計算。但是這裡面存在着一個問題,就是當一個點已經被算到屬于某條邊的拼車事件中去時,那麼其在其它邊上的拼車事件就不能被計算(我們在這裡使用的政策是隻有小id的點負責計算邊)。對于三角形的計算也應該同樣遵循這樣的規則。首先計算邊的算法我們叫做independentedgecount,其table schema為:

計算邊數量的核心算法為:

用來儲存三角形計數的table的schema為:

create table nyc_taxi_triangle(vid bigint, count bigint);

三角形的計算我們使用odps标準的例子,具體見[4],但是因為不能重複将已經計算的三角形作為拼車的例子,是以我們需要将算法進行改進,計算過的三角形不再列入進一步的計算中,同時因為我們使用的圖為無向圖,是以相比較[4]的例子,我們隻需要兩輪疊代,經過改進後的算法代碼如下:

計算獨立三角形(邊數)的odps指令為:

jar -resources prepare_graph.jar,log4j-1.2.17.jar,rt.jar -classpath /users/stplaydog/gitlocal/odps_clt/jars/prepare_graph.jar nyctaxidatagraphanalysis/trianglecount nyc_taxi_graph nyc_taxi_triangle;

我們找到的獨立邊的個數為168,841,988,獨立三角形的個數為102,091,976,這樣可以推論在現有的拼車标準下,可拼車傾向的比例為:

兩人拼車:168,841,988*2/866,796,462 = 38.96%

我們想要分析具體在哪個時間段的拼車需求比較多,那麼先需要把這個獨立邊和獨立三角形的資訊映射回原表上,具體使用join操作:

在quick bi上建立一個sql資料源:

得到的圖表如下:

使用MaxCompute進行紐約的士拼車分析前言技術方案資料分析引用

三人拼車:102,091,976*3/866,796,462 = 35.33%

使用同樣的流程獲得的圖為:

使用MaxCompute進行紐約的士拼車分析前言技術方案資料分析引用

可以看到,兩人和三人拼車基本遵循類似的規律,就是在晚上7,8,9點時下班時左右達到高峰,不同的是,三人拼車在早上7,8,9點左右會有一個與下午類似的高峰。

[1] https://github.com/toddwschneider/nyc-taxi-data 

[2] maxcompute sql row_sequence 實作列自增長 https://yq.aliyun.com/articles/118901?spm=5176.8091938.0.0.cxytzs

[3] guttman, a. (1984). "r-trees: a dynamic index structure for spatial searching". 

繼續閱讀