桌面輕量級資料處理指令碼

cainiao_M發表於2020-12-03

幾乎所有的程式語言都能處理資料,但有些過於通用,缺乏專業的結構化計算函式,用於資料處理時程式碼比較繁瑣,比如C++、JAVA,這些語言更適合去實現大型專業的專案。還有專業的數學計算語言工具,如MATLAB和R,也有部分函式適合處理資料,但還是專業性過強,不適合日常資料處理。我們在這裡挑選了四種適合桌面業務的輕量級資料處理語言來介紹和討論:以MySQL為代表的輕量小型資料庫、Excel VBA、Python pandas、esProc。

下面,就讓我們深入瞭解這些程式語言,看看它們的真實能力到底如何。

MySQL

小型資料庫比如HSQLDB、DerbyDB、SQLite、MySQL等,都可以在桌面輕鬆執行。這裡以最常見的MySQL為例,討論這種資料處理指令碼的特點。

安裝配置方面,MySQL因為有綠色版的存在,所以安裝配置非常方便。偶爾遇到許可權目錄之類的環境問題,雖然只能用安裝版來解決,但MySQL的安裝嚮導非常友好,過程相當輕鬆。

互動介面方面,MySQL自帶的命令列工具可以正常執行SQL,但有點簡陋,所以很多人會用第三方工具來代替(比如Navicat、Toad)。這樣看來,MySQL自帶的互動介面算不上成功。

當然,對於一款程式語言來講,資料處理能力才是核心。MySQL的資料處理能力,本質上也就是 SQL的能力。

經過半個多世紀的迭代改進,SQL語句已經在其模型框架內接近極致,幾乎每種基本演算法都能找到對應的SQL表示式,這便極大地降低了資料處理的門檻。近兩年,MySQL又開始支援視窗函式、with子句、儲存過程,其SQL能力已可比肩大型資料庫。比如下面的基本演算法:

| /過濾,表emp儲存各部門員工資訊/select eid, name, deptid, salary from emp where salary between 8000 and 10000 and hireday>=’2010-01-01’/排序/select * from emp order by salary /去重/select distinct deptid from emp/分組彙總,表share儲存某支股票每天的收盤價/select year(sDate),month(sDate),max(price) from share group by year(sDate),month(sDate)/關聯,表dept儲存部門資訊/select e.name, e.salary, d.deptname from emp e inner join dept d on e.deptid=d.deptid/開窗,按工資對各部門內的員工進行排名/select eid, name, deptid, salary, rank()over( partition by deptid order by salary desc) rk from emp |

在基本運算方面,MySQL可以說是無可挑剔。但日常資料處理中還存在不少複雜情況,這時候MySQL(其實也就是SQL)並不擅長。

多步驟的過程性演算法是SQL的弱項,比如根據員工表emp,計算出人數最多和最少的兩個部門。直觀思考的話,這個問題應該分2步,先把emp表按部門分組,計算出每部門人數,然後按人數逆序排序,頭尾兩個就是人數最多和最少的部門。但用SQL計算的時候,你會發現必須把演算法複雜化,變成4步才能計算出結果。第一步不變,計算出各部門人數。第二步:用max求出最多的人數,然後用巢狀查詢或關聯查詢反推出最多人數對應的部門。第三步:用類似第二步的演算法,再計算出人數最少的部門。第四步:用union合併第二步和第三步的計算結果:

| with tmp as ( select dept, count(*) total from employee group by dept),deptmax as( select dept from tmp where total=( select max(total) from tmp) ),deptmin as( select dept from tmp where total=( select min(total) from tmp) )select dept from deptmaxunionselect dept from deptmin |

這個程式碼寫出來就有些冗長且費解了。

SQL發明於大約50年前,考慮欠缺在所難免,除了多步驟過程性演算法,還有很多日常資料處理中的複雜情況都是SQL不擅長的,其中就包括有序運算,比如根據股價表share,計算該股票最長連續上漲了多少交易日。使用SQL計算時,你會發現很難直接表達連續上漲這個概念,只能轉變思路來回繞彎,解題過程非常痛苦,具體是:先計算從初始時刻開始累計的不漲日數,不漲日數相同的交易日即是連續上漲,針對連續上漲分組可計算出最大連漲區間。事實上,此類演算法對SQL專家都是難題,即使專家寫出正確的程式碼,普通使用者也難以真正讀懂。

| select max(consecutive_days)from (select count(*) consecutive_days from (select sum(updown_flag) over(order by sdate) no_up_days from (select sDate, case when price>LAG(price) over(order by sDate) then 0 else 1 end updown_flag from share) )group by no_up_days) |

這已經是使用了有視窗函式的最新版本,如果是早期版本就會更麻煩。

再比如按指定的集合成員對齊:表orders儲存訂單記錄,需要按星期日到星期六的順序,統計大訂單的當日金額,當日無訂單則顯示空值。其中,大訂單指金額超過15000的訂單。SQL解決此類問題,只能用拼假表的技巧把星期列表變成記錄集合,再用該假表左關聯被對齊的表,實現過程非常繁瑣:

| with std as( select 1 No,’Sun.’ name from dual union select 2 ,’Mon.’ from dual union select 3 ,’Tues.’ from dual union select 4 ,’Wed.’ from dual union select 5 ,’Thur’ from dual union select 6 ,’Fri.’ from dual union select 7 ,’Sat.’ from dual )select std.No,std.name,data.total from std left join ( select DAYOFWEEK(orders.orderdate) No,sum(amount) total from orders where amount>15000 group by DAYOFWEEK(orders.birthday)) dataon std.No=data.No order by std.No |

類似的例子還有很多,其根本原因還是SQL太古老,設計之初就沒考慮現代需求的複雜性,後來雖然用with語句、儲存過程、視窗函式打了很多補丁,有一些改善,但始終無法全面突破最初的限制。

SQL還有個封閉性的缺點, 即只能計算內部庫表,卻很難讀寫外部資料來源。這倒不是SQL這種指令碼的問題,而是資料庫都實現成這樣了。

眾所眾知,資料處理的第一步是讀取源資料,最後一步是輸出成目標資料格式。對外部資料來源種類支援的多少,是判斷一款資料處理指令碼優劣的重要標準。遺憾的是,MySQL只能讀取(無法寫)一種外部資料來源,即文字檔案(CSV)。這也就罷了,問題是操作步驟還很麻煩,比如將標準格式的emp.csv匯入資料庫,須經過以下四步:

| /切換庫、建表、入庫,最後建主鍵索引,可大幅提升匯入速度/mysql>use testdb;mysql>create table emp (-> empid int(10) not null,-> name varchar(50), -> deptid int(10), -> salary float, -> sex varchar(1), -> birthday date,-> hireday date)CHARSET = utf8;mysql>LOAD DATA INFILE ‘d:\data\emp.csv’ INTO TABLE emp ->CHARACTER SET utf8 ->FIELDS TERMINATED BY ‘,’ ->LINES TERMINATED BY ‘\r\n’ ->IGNORE 1 LINES;mysql>ALTER TABLE emp ADD PRIMARY KEY (empid); |

上面的實現過程之所以異常繁瑣,還是因為SQL封閉,設計之初沒考慮讀取文字檔案,後來才硬加了這種額外操作而已。

使用Navicat等第三方工具可以讓MySQL支援更多的資料來源,但本質上是先將其他資料來源轉為文字檔案,再將文字檔案匯入MySQL。這種非原生的、補丁摞補丁的方式毛病很多,其中老舊格式雖然支援得最好,但現在幾乎沒人用了,比如DBase、Paradox;新一點的Excel雖然表面上也支援,但實際要求很苛刻,成功匯入的機率低;最近幾年開始支援json,但僅限特殊的二維格式;至於現代資料處理中常用的資料來源,Navicat基本上都不支援。

SQL還有個除錯困難的問題,會嚴重製約程式碼的編寫效率。

對於只存在於教科書中的簡單演算法,區區三五行而已,不需要除錯,但現在資料處理過程越來越複雜,經常用到上百行帶著巢狀的SQL, 不能除錯就意味著難以理解難以維護,也意味著效率的嚴重降低。

SQL雖然擅長對庫內資料進行一般性處理,但對於眾多的外部資料來源以及現代複雜演算法,確實是心有餘而力不足。好在新指令碼總會順勢而生,下面,就讓我們瞭解下PC時代的桌面輕量級資料處理指令碼。

Excel VBA

隨著30年前PC的崛起,計算機使用者的主角由科學家變成了普通人,針對普通人的特點,一款無需程式設計也能處理資料的桌面工具順勢而生,這就是聞名世界的Excel。最近幾年,Excel又加入了Power Query等元件,不僅極大地豐富了資料來源的支援種類,同時也大幅增強了資料處理的能力。

毫不誇張地說,Excel是當前非程式設計者最強大的資料處理工具。

但不能程式設計會嚴重限制Excel的處理能力,所以VBA也很快誕生。VBA的目的很明確:透過程式設計增強Excel的靈活性,使Excel的資料處理能力不再受限。

問題來了,VBA的目的達到了嗎?可以說達到了,也可以說沒達到。

作為可程式設計的資料處理指令碼,VBA幾乎無所不能,理論上的確可以讓Excel的資料處理能力不再受限,尤其在過程性演算法、可除錯方面,對比SQL可以說是翻天覆地的增強。從這一點來講,VBA的目的達到了。但實際上, VBA仍然屬於通用開發語言(訪問單元格時有專用函式),並沒有專門的結構化計算函式,所以用VBA處理資料是件繁瑣且痛苦的事情,很多時候遠不如SQL方便。

比如最基本的讀檔案:orders.csv是逗號分隔的文字,首行是列名,將列名和資料讀入到當前sheet。程式碼就有這麼長:

| Const Title As String = “IMPORT CSV TEST”Sub fMain() Dim fTextDir As String Dim pintLen As Integer Dim pstrValue As String Dim rowIndex As Integer Dim i As Integer rowIndex = 1 pstrValue = “” pintLen = Len(Title) fTextDir = “D:/orders.csv” Open fTextDir For Input As #1 Do While Not EOF(1) ‘ loop every line Line Input #1, currLine If Right(currLine, pintLen) = Title Then Range(Cells(rowIndex, 1), Cells(rowIndex, 4)).Select With Selection .HorizontalAlignment = xlCenter .VerticalAlignment = xlTop .WrapText = False .Orientation = 0 .AddIndent = False .ShrinkToFit = False .ReadingOrder = xlContext .MergeCells = True .RowHeight = 27.75 .Font.Name = “Arial” .Font.Size = 18 .Font.Bold = True .FormulaR1C1 = Title .Interior.ColorIndex = 6 .Interior.Pattern = xlSolid End With Else rowDataArr = Split(currLine, “,”) For i = 0 To UBound(rowDataArr) Cells(rowIndex, i + 1).Select With Selection .HorizontalAlignment = xlCenter .VerticalAlignment = xlTop .WrapText = False .Orientation = 0 .AddIndent = False .ShrinkToFit = False .ReadingOrder = xlContext .MergeCells = True .RowHeight = 20 .Font.Name = “Arial” .Font.Size = 12 .Font.Bold = False .FormulaR1C1 = rowDataArr(i) End With Next i End If rowIndex = rowIndex + 1 Loop Close #1 End Sub |

上面例子中,資料格式已經很規整,但讀取的程式碼依舊麻煩,如果遇到不太規範的髒資料,比如跳過空白行、特殊分隔符、一條記錄對應多行等,可以想象處理起來只會更加痛苦。

需要指出的是,雖然Power Query支援的資料來源種類非常多,但只有用嚮導介面讀取固定資料時才會方便,萬一要用VBA動態讀取,那又是噩夢一場。除此之外,Power Query只支援讀取,不支援寫出,如果需要把計算結果寫出到目標資料來源,基本只能用VBA的方式(CSV除外,可直接匯出)。

不僅基本的讀資料來源很麻煩,就連基本的結構化演算法也很難實現。比如最簡單的分組彙總:對sheet1的A列分組,對B列求和。演算法中已經省略了讀取源資料的步驟,但仍然需要寫出大片難懂的程式碼:

| Public Sub test() Dim Arr Dim MyRng As Range Dim i As Long Dim Dic As Object Set MyRng = Range(“A1”).CurrentRegion Set MyRng = MyRng.Offset(1).Resize(MyRng.Rows.Count - 1, 2) Set Dic = CreateObject(“Scripting.dictionary”) Arr = MyRng For i = 1 To UBound(Arr) If Not Dic.exists(Arr(i, 1)) Then Dic.Add Arr(i, 1), Arr(i, 2) Else Dic.Item(Arr(i, 1)) = Dic.Item(Arr(i, 1)) + Arr(i, 2) End If Next i Sheet2.Range(“A1”) = “subject” Sheet2.Range(“A2”).Resize(Dic.Count) = Application.WorksheetFunction.Transpose(Dic.keys) Sheet2.Range(“B1”) = “subtotal” Sheet2.Range(“B2”).Resize(Dic.Count) = Application.WorksheetFunction.Transpose(Dic.items) Set Dic = Nothing End Sub |

Excel對非程式設計者而言,的確是個強大的資料處理工具,但VBA並未顯著增強Excel的能力,對程式設計者尤其是桌面分析師而言如同雞肋。之所以出現這樣尷尬的局面,是因為VBA雖然在過程性方面有進步,但在結構化演算法方面並未趕上SQL。

下面,就讓我們看看網際網路時代的資料處理指令碼,能否在結構化演算法方面有所改進。

Python Pandas

Python的歷史比VBA更長,但直到互聯時代來臨,Python得以利用開源社群的力量,不斷擴充各類第三方函式庫,人們才開始注意到它的存在。在眾多明星級函式庫中,就包括用於資料處理的Pandas。

Python的初衷是易讀易寫,Pandas在函式級別上很好地保持了這種風格,每一個函式都是介面清晰、簡單易用、功能強大的典範。比如基本的結構化計算函式:

| df.query(‘salary>8000 and salary<10000’) #過濾,df是DataFrame型別df.sort_values(by=”salary”,ascending = True) #排序df.groupby(“deptid”)[‘salary’].agg([len, np.sum, np.mean]) #分組彙總 |

由於開源社群廉價而高效的生產力,Pandas所包含的函式非常之多,基本涵蓋了常用的結構化演算法。由於繼承了Python的語法風格,呼叫Pandas函式的方法也非常簡單。兩個因素加在一起,讓Pandas可以快速而輕鬆地完成基本的資料處理任務。

在結構化計算函式方面,Pandas不比SQL差,在外部資料支援程度方面,Pandas則比SQL強大太多了。比如用於讀取csv/txt的函式read_csv,用法如下:

| import pandas as pddf=pd.read_csv(‘D:/emp.csv’) #return as a DataFrame |

上述是讀取標準csv的用法,對於其他常規格式,比如首行非列名、跳過N行讀取,該函式都可透過設定引數實現,用法同樣簡單。

除了csv,Pandas還可以讀取資料庫、json檔案、Excel、網頁等等幾乎所有外部資料來源,同樣只需簡單的函式引用。值得一提的是,Pandas不僅讀取源資料很方便,寫出到目標資料來源同樣方便。這些函式介面清晰、呼叫方便,充分體現了Python易讀易寫的特點。

作為標準的程式性語言,Pandas還有一個明顯強於SQL的優點:Pandas(實際是Python)支援斷點、單步、跳入、跳出等標準除錯手段,可以快速排除程式碼中的錯誤,可以輕鬆維護複雜演算法,因此開發效率要遠高於SQL。

Pandas的主要優勢在於豐富而易用的庫函式,包括各類結構化計算函式和多種外部資料來源訪問函式,這對初學者很有吸引力力。但如果深入學習Pandas的話,就會發現一個嚴重的問題:單獨使用每個基本函式時,的確簡單易用;一旦要用多個函式配合,完成實際的日常演算法時,程式碼就變得複雜難用起來。

比如:split_field.csv是tab分隔的文字檔案,處理前有兩個欄位,ID和ANOMOALIES,需要將ANOMOALIES欄位按空格拆分為多個字串,使每個字串和原ID欄位形成新的記錄,示意如下:

處理前的資料(split_field.csv)

| ID | ANOMALIES |
| 1 | A1 B1 C1 D1 |
| 2 | A2 |
| 3 | A3 B3 C3 |
| 4 | A3 B4 D4 |
| … | … |

處理後的資料

| ID | ANOMOLIES |
| 1 | A1 |
| 1 | B1 |
| 1 | C1 |
| 1 | D1 |
| 2 | A2 |
| … | … |

實現上述演算法的程式碼如下:

| import pandas as pdimport numpy as npsplit_field = pd.read_csv(‘C:\split_field.csv’,sep=‘\t’)split_dict = split_field.set_index(‘ID’).T.to_dict(‘list’)split_list = []for key,value in split_dict.items(): anomalies = value[0].split(‘ ‘) key_array = np.tile(key,len(anomalies)) split_df = pd.DataFrame(np.array([key_array,anomalies]).T,columns=[‘ID’,‘ANOMALIES’]) split_list.append(split_df)split_field = pd.concat(split_list,ignore_index=True)print(split_field) |

上面例子屬於字串拆解,雖然是Pandas的長項,但程式碼還是有點複雜,如果遇到Pandas不那麼擅長的有序計算,程式碼只會更加難懂。比如:duty.csv記錄著每日值班情況,一個人通常會持續值班幾個工作日,之後再換人,現在請根據duty.csv依次計算出每個人連續的值班情況,示意如下:

處理前(duty.csv)

| Date | name |
| 2018-03-01 | Emily |
| 2018-03-02 | Emily |
| 2018-03-04 | Emily |
| 2018-03-04 | Johnson |
| 2018-04-05 | Ashley |
| 2018-03-06 | Emily |
| 2018-03-07 | Emily |
| … | … |

處理後

| name | begin | end |
| Emily | 2018-03-01 | 2018-03-03 |
| Johnson | 2018-03-04 | 2018-03-04 |
| Ashley | 2018-03-05 | 2018-03-05 |
| Emily | 2018-03-06 | 2018-03-07 |
| … | … | … |

| | |

實現上述演算法的pandas程式碼如下:

| import pandas as pdimport numpy as npduty = pd.read_csv(‘C:\duty.csv’,sep=’\t’)name_rec = ‘’start = 0duty_list = []for i in range(len(duty)): if name_rec == ‘’: name_rec = duty[‘name’][i] if name_rec != duty[‘name’][i]: begin = duty[‘date’].loc[start:i-1].values[0] end = duty[‘date’].loc[start:i-1].values[-1] duty_list.append([name_rec,begin,end]) start = i name_rec = duty[‘name’][i]begin = duty[‘date’].loc[start:i].values[0]end = duty[‘date’].loc[start:i].values[-1]duty_list.append([name_rec,begin,end])duty_b_e = pd.DataFrame(duty_list,columns=[‘name’,’begin’,’end’])print(duty_b_e) |

從上面的例子可以看出,Pandas只有基本函式才具有易讀易寫的特點,一旦遇到實際工作中的日常演算法,就會變得難讀難寫。但實際工作中,源資料格式不可能總是標準的,資料處理演算法也不可能只是最基本的過濾和排序。實際工作中,我們會遇到各種各樣未知的情況,我們必須用基本函式自由組合,讓資料按照一定的規則去清洗、轉換、計算,才能獲得我們需要的處理結果。

Pandas實現日常演算法時之所以變得難讀難寫,主要還是因為Python和開源社群之間的關係過於鬆散。Pandas只是眾多開源社群之一,其權力只限於Pandas函式內部,Python不可能讓一個社群去改進函式之間的呼叫語法。面對五花八門的函式庫,Python團隊也沒有精力去一一瞭解,所以很難從整體上改進語法,讓函式之間的配合更簡單方便。

Pandas處理超出記憶體的資料也很困難。

如果資料量較大(指超出記憶體,而不是Big Data),一般要用迴圈的辦法來處理,即:每次讀取並計算少量資料,再保留本次計算的中間計算結果,迴圈結束後合併多箇中間計算結果(比如過濾),或對合並結果做二次計算(比如分組彙總),如此形成最終計算結果。可以看到,即使是基本結構化演算法,資料量大時也很繁瑣,更別說涉及多種資料的關聯、歸併、集合等演算法,或組合多種基本演算法的實際日常演算法。

為了簡化大資料量的計算,資料處理指令碼應當在底層提供某種機制,向下自動實現內外存交換,向上隱藏繁瑣的計算細節,允許桌面分析師用類似處理小資料量的語法,直觀地處理較大的資料量。但遺憾的是,Python沒有為Pandas提供這種底層支援,這就導致Pandas實現較大資料量的計算時,必須由桌面分析師自己實現底層邏輯,程式碼因此異常繁瑣。

比如: orders.csv記錄著電商的訂單資料,需要計算每個銷售員銷售額最大的3筆訂單。Pandas程式碼如下:

| import pandas as pdimport numpy as npchunksize=1000000order_data = pd.read_csv(d:\orders.csv’,iterator=True,chunksize=chunksize)group_list = []for chunk in order_data: for_inter_list = [] top_n = chunk.groupby(by=’sellerid’,as_index=False) for index,group in top_n: group = group.sort_values(by=’amount’,ascending=False).iloc[:3] for_inter_list.append(group) for_inter_df = pd.concat(for_inter_list,ignore_index=True) group_list.append(for_inter_df)top_n_gr = pd.concat(group_list,ignore_index=True).groupby(by=’sellerid’,as_index=False)top_n_list=[]for index,group in top_n_gr: group = group.sort_values(by=’amount’,ascending=False).iloc[:3] top_n_list.append(group)top_3 = pd.concat(top_n_list)print(top_3) |

實現大資料量計算時,優秀的資料處理指令碼不僅會提高程式碼的表達效率,也會想辦法提高程式碼的執行效率,比如壓縮分段、多執行緒並行等。這些底層最佳化手段應當由Python統一提供,才能保證各類三方庫函式的統一和穩定,但Python沒這樣做,只能由開源社群自己解決,比如joblib等開源社群就實現了多執行緒並行。

第三方多執行緒庫函式終於出現了,Pandas應該跑得更快吧?

錯!Python和開源社群的關係很鬆散,開源社群之間的關係更鬆散,所以Pandas很難和第三方多執行緒庫函式配合,也就談不上更快。比如上面的例子,理論上雖然能改成多執行緒,但實際上很難實現。

Python和開源社群的關係過於鬆散,還會導致Pandas訪問資料來源的困難。

前面提到過,Pandas支援絕大多數資料來源,之所以如此方便,是因為每種資料來源都有對應的開源社群和第三方函式庫。但問題在於:每種資料來源對應的開源社群不止一個,第三方函式庫也不止一個。比如MySQL資料庫,常見的函式庫就有三種:sqlalchemy、MySQLdb、PyMySQL。另外,oracle、MSSQL、HSQLDB…幾乎每種資料庫都有多個開源社群的多種函式庫可用,而且每種函式庫的使用方法都不一樣!

對於專業程式設計師來說,多種選擇也許是件好事,但對於桌面分析師而言,沒人想用複雜的pip命令去尋找並部署不同的函式庫,也沒人想去測試這些函式庫的區別,我們只想要這樣的桌面輕量級資料處理指令碼:可以用簡潔且統一的語法訪問不同的資料來源,然後迅速處理資料。

Pandas的優點很明顯:函式種類豐富,但缺點也很明顯:日常演算法編寫複雜、大資料量演算法編寫繁瑣、對桌面分析師不友好。那麼,有沒有一種桌面輕量級資料處理指令碼,不僅具備專業而豐富的結構化計算函式,還能彌補Pandas的缺點?下面就會講到這樣的指令碼語言。

esProc

與Pandas類似,esProc也具有豐富的結構化計算函式,比如:

| | A | B |
| 1 | =file(“d:/emp.csv”).impor@tc() | /從檔案讀入員工,序表型別 |
| 2 | =A1.select(salary>8000 && salary<10000) | /過濾 |
| 3 | =A1.sort(-salary) | /逆序排序 |
| 4 | =A1.groups(deptid;sum(salary),avg(salary)) | /分組彙總 |
| 5 | =A1.group(deptid).conj(~.sort(salary)) | /開窗,按工資對各部門內的員工進行排名 |
| 6 | =connect@l(“mssql”).query(“select * from dept”) | /從資料庫讀入部門,序表型別 |
| 7 | =A1.join@i(deptid,A6:deptid,deptname) | /內關聯,檔案-資料庫 |

上述程式碼A1中,import是讀取標準csv的用法,對於其他常規格式,比如首行非列名、跳過N行讀取,該函式都可透過設定引數實現,用法同樣簡單。

與Pandas類似,esProc還可以讀取資料庫(上述程式碼A6)、json檔案、Excel、網頁等等幾乎所有外部資料來源,且寫出到目標資料來源同樣方便。

作為標準的程式性語言,esProc同樣支援斷點、單步、跳入、跳出等標準除錯手段,從而提高開發效率。

除了上述相同之處, esProc和Pandas也有很多不同,其中最主要的區別在於, esProc是由獨立團隊維護的閉源軟體,而不是開源社群的第三方庫函式,也不存在一個鬆散的上級組織。esProc可以毫無束縛地從全域性角度設計語法,使函式之間以最大的靈活度搭配組合,從而快捷方便地解決日常工作中遇到的問題。

比如規範化特殊的資料格式:將split_field.csv的 ANOMOALIES欄位按空格拆分為多個字串,從而使一行記錄變多行。程式碼非常簡單,如下:

| | A |
| 1 | =file(“C:\split_field.csv”).import@t() |
| 2 | =A1.news(ANOMALIES.split(“ “);ID,~:ANOMALIES) |

再比如,根據duty.csv依次計算出每個人連續的值班情況,程式碼依然簡單:

| | A |
| 1 | =file(“C:\duty.csv”).import@t() |
| 2 | =A1.group@o(name) |
| 3 | =A2.new(name,.m(1).date:begin,.m(-1).date:end) |

可以看到,同樣的日常演算法, esProc要比Python簡單許多,稱得上是真正的易讀易寫。

有了統一的設計,esProc可以從底層提供遊標機制,允許桌面分析師用類似處理小資料量的語法,直觀地處理較大的資料量。比如,根據orders.csv計算每個銷售員銷售額最大的3筆訂單。程式碼如下:

| | A |
| 1 | =file(“d:\orders.csv”).cursor@tc() |
| 2 | =A1.groups(sellerid;top(3; -amount):top3) |
| 3 | =A2.conj(top3) |

有了統一的設計,esProc很容易從底層支援多執行緒並行,改動程式碼提升效能很方便。比如把前面的程式碼改為多執行緒並行:

| | A | B |
| 1 | =file(“E:\orders.csv”).cursor@tmc(;4) | /4執行緒並行 |
| 2 | =A2.groups(sellerid;top(3; -amount):top3) | |
| 3 | =A3.conj(top3) | |

有了統一的設計,esProc可以用設計一致的介面訪問資料庫,而不是像Pandas那樣用不同的第三放函式庫。另外,對於任意種類的資料來源,esProc可以返回統一的資料型別(序表),從而直接進行互動運算,而不是像Pandas那樣,只能對個別資料來源用統一資料型別(dataframe),其他資料來源只能先寫成csv檔案,再讀成dataframe。對於桌面分析師來講,這意味著簡單易用和快速開發,不必像Python那樣到處下載並比較第三方庫函式。

經過前面的比較,我們可以看到esProc是一款對桌面分析師非常友好的輕量級資料處理指令碼,不僅具備豐富的結構化函式,還可以輕鬆實現日常工作中較複雜的演算法,並簡化大資料量演算法的編寫。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章