摘要:另外一個我們同時使用兩種語言的原因是已有的統計學工具與包。對另一些為讀者寫數據科學工具的人來說他們從一開始就考慮了這些跨語言。和實際上是用實現的這是條阻力最小的路徑。無論是哪個贏得這場語言戰爭,和都將保持在數據科學屆的地位。
概述
幾周前,我有幸在 Scipy 大會上發表了 Civis如何使用Python和R的演講。為什么要在一個Python大會上大談R呢?這是要挑起一個Python和R語言的一場戰爭嗎?不是的!討論哪個語言比較好簡直是浪費時間。在 Civis,我們很愉快地同時使用這兩種語言,不僅僅是在我們日常工作中解決數據科學問題,也用它們來寫一些其他工具。下面是我在SciPy 大會上的一些討論。
問題現狀我們 Civis 的同事有著十分不同的學術背景。我效力的研發團隊有一個物理學家、一個經濟學家、兩個統計學家以及一位土木工程師組成。在 Civis,每個人在數據科學上都會做一些不同內容的工作,有的領域是R比較流行,有的領域是Python比較流行,還有的一些是Matlab。在這種場景下只支持一種語言并不是一個明智的選擇。遷移到一門新語言上會花費許多時間,拋開在學院或者業界多年的技能回報,允許人們使用它們所熟悉的工具可以確保大家有更高的生成效率。
另外一個我們同時使用兩種語言的原因是已有的統計學工具與包。在解決數據科學問題上,我們經常遇到在某些特定管道上需要某一種特定語言。我們的調研管道是一個很好的例子。確保隨機樣本具有全集代表性是需要一個被稱為 raking 的過程的,傳統上,Python 在社會科學上并不流行,因此我們只會用R來完成這件事情。當然調查也包括了QA的全文檢索,在某種程度上來說R在NLP社區上并不是很流行,因此這個部分將會由Python來完成。而分析調查數據只是我們在Civis解決問題的一個小步驟。
結合許多不同的語言來實現工作流是具有挑戰性的。數據科學平臺幫助我們可以提交一連串任務節點,然后交由基礎設施負責獨立調用每個任務節點,且前后不依賴。但是這并不是一個十分理想的情況。原因有二,其一,這樣做整個任務就顯得破碎化,稍有修改某個任務,往往會導致全局失敗,而且任何人在這個分布式系統中所做的工作都只了解局部情況,而不知道全局情況。第二,這樣做并不高效。在兩個語言中切換通常需要將數據以特定格式加載到磁盤上(通常最壞的情況是csv格式)。這樣不僅僅是解析成本比較高,而且還會丟失一些類型信息。
解決方案我概述了在Civis遇到的種種問題,但是到底什么是理想的狀態呢?最完美的解決方案是我們可以無縫切換工具和語言。許多熟悉Python的人喜歡用Python做數據分析,R也是類似的。事實證明這是完全有可能實現,有相當數量的項目已經開始作為跨語言工具:TensorFlow, XGBoost, 和 Stan 都在Civis被廣泛運用。移植或安利一個已有的工具也是可能的,我們已經成功地完成了glmnetR包的安利。
對另一些為讀者寫數據科學工具的人來說,他們從一開始就考慮了這些跨語言。有一些方法可以做到這一點,但我個人最喜歡的是用C語言來寫底層,然后使用各自的Python和R C api做一些綁定/封裝。Python和R實際上是用C實現的,這是條阻力最小的路徑。C是一門古老語言,C語言社區已經演進出了一些強大的工具鏈。晦澀的編譯器錯誤消息已經成為了過去時,GCC和Clang(最流行的編譯器)給友善的消息反饋(Clang網站可以看到栗子)。現在還有各種各樣的“消毒液”來輔助捕獲內存泄漏等常見錯誤或未定義的行為(llvm文檔)。
案例下面我們通過一個小例子,用C編寫一個函數,使這可調用的Python和R。代碼以及幻燈片從我的GitHub上可以找到。
Python我們將下面的Python函數轉換為C:
def tally(s): total = 0 for elm in s: total += elm return totalC
這是相同的功能用C實現:
#includedouble tally(double *s, size_t n) { double total = 0; for (size_t i = 0; i < n; i++) { total += s[i]; } return total; }
注意到它看起來并不是都不同的Python函數。當然,除了有一些類型注解和額外的語法噪音大括號外,我們還必須跟蹤數組的長度,但整體邏輯是一樣的。
接下來,我們需要實現一個Python綁定,允許用戶調用這個函數就像任何其他Python函數。
Cython#include#include "Python.h" #include "tally.h" static PyObject *tally_(PyObject *self, PyObject *args) { PyObject *buf; if (!PyArg_ParseTuple(args, "O", &buf)) { return NULL; } Py_buffer view; int buf_flags = PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT; if (PyObject_GetBuffer(buf, &view, buf_flags) == -1) { return NULL; } if (strcmp(view.format,"d") != 0) { PyErr_SetString(PyExc_TypeError, "we only take floats :("); PyBuffer_Release(&view); return NULL; } double result = tally(view.buf, view.shape[0]); PyBuffer_Release(&view); return Py_BuildValue("d", result); } static PyMethodDef MethodTable[] = { {"tally", &tally_, METH_VARARGS, "Compute the sum of an array"}, { NULL, NULL, 0, NULL} }; static struct PyModuleDef tally_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "tally_", .m_size = -1, .m_methods = MethodTable }; PyMODINIT_FUNC PyInit_tally_(void) { return PyModule_Create(&tally_module); }
這里有很多實現的方法,但大多數只是Python模塊的一部分樣板代碼。
在最上面,我們定義了一個函數,它接受一個Python對象,并且檢查這是一個適當類型的數組,再調用我們的計數功能,然后返回結果。其余的代碼模塊定義,告訴Python解釋器我們計數功能的名稱和它的參數類型。
R的過程非常相似,但是更加簡潔:
#include#include #include #include "tally.h" SEXP tally_(SEXP x_) { double *x = REAL(x_); int n = length(x_); SEXP out = PROTECT(allocVector(REALSXP, 1)); REAL(out)[0] = tally(x, n); UNPROTECT(1); return out; } static R_CallMethodDef callMethods[] = { {"tally_", (DL_FUNC)&tally_, 1}, {NULL, NULL, 0} }; void R_init_tallyR(DllInfo *info) { R_registerRoutines(info, NULL, callMethods, NULL, NULL); }
這里需要的代碼量顯著減少,因為R和Python類型系統有所不同,沒有真正標量類型,所以我們不需要做相同級別的檢驗/驗證用戶輸入我們在上面的Python示例。剩下的代碼大致相同,我們定義一個組函數可在R編譯。
總結一個真實世界的例子一定會更加復雜,但整個過程并不是那么困難。在編寫跨語言工具時有幾件事要記住:
如果你打算在兩者之間共享函數就不要依賴宿主語言的api(R或Python)代碼。
使用錯誤碼來傳遞異常提示,不要直接調用退出或者在宿主語言里面才處理異常。
最好用宿主語言負責內存分配和重分配,這意味著你的C/C++代碼應該要略過預先分配的內存和輸出過程。
相信編譯器,你也應該重視編譯器的錯誤和警告。如果代碼在編譯時有警告那代碼就不算寫完。
無論是哪個“贏得”這場語言戰爭,Python和R都將保持在數據科學屆的地位。這意味著為工具開發者不能忽視的另外一門語言,構建有用的工具就得保證這兩種語言都可以使用。一個簡單的方式是用C或c++編寫大量代碼,然后用 C 的 API的為兩種語言提供封裝。
參考資料GitHub Scipy 2016
Linkedin: Python or R?
原作者:Bill Lattner 翻譯:Harry Zhu
英文原文地址:Forget Python vs. R: how they can work together作為分享主義者(sharism),本人所有互聯網發布的圖文均遵從CC版權,轉載請保留作者信息并注明作者 Harry Zhu 的 FinanceR專欄:https://segmentfault.com/blog...,如果涉及源代碼請注明GitHub地址:https://github.com/harryprince。微信號: harryzhustudio
商業使用請聯系作者。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/38123.html
摘要:概述在真實的數據科學世界里,我們會有兩個極端,一個是業務,一個是工程。偏向業務的數據科學被稱為數據分析,也就是型數據科學。所以說,同時學會和這兩把刷子才是數據科學的王道。 showImg(https://segmentfault.com/img/bVAgki?w=980&h=596); 概述 在真實的數據科學世界里,我們會有兩個極端,一個是業務,一個是工程。偏向業務的數據科學被稱為數據...
摘要:對于異常機制的合理運用是直接關系到碼農飯碗的事情所以,本文將具體介紹一下和的異常處理機制,闡明二者在異常處理機制上的異同。下面將具體介紹二者的異常處理機制。 概述 showImg(https://segmentfault.com/img/remote/1460000006760426); 異常處理,是編程語言或計算機硬件里的一種機制,用于處理軟件或信息系統中出現的異常狀況(即超出程序正...
摘要:概述工欲善其事必先利其器,如果現在要評選數據科學中最好用的編輯器注意一定是可以通過訪問的,和一定是角逐的最大熱門,正確使用編輯器可以很大地提升我們的工作效率。 概述 showImg(https://segmentfault.com/img/bVAdol); 工欲善其事必先利其器,如果現在要評選數據科學中最好用的Web 編輯器(注意一定是可以通過Web訪問的),RStudio和Jupyt...
摘要:則在讀取數據時將兩個中文字段混淆成了一個字段,導致整個數據結構錯亂。三條路子全軍覆沒,這讓我情何以堪,好在使用的經驗頗豐,通過中文的轉換和切割就輕松解決了這個問題。 概述 showImg(https://segmentfault.com/img/bVylLL); 在現實場景中,由于數據來源的異構,數據源的格式往往是難以統一的,這就導致大量具有價值的數據通常是以非結構化的形式聚合在一起的...
閱讀 689·2023-04-25 19:53
閱讀 4262·2021-09-22 15:13
閱讀 2565·2019-08-30 10:56
閱讀 1320·2019-08-29 16:27
閱讀 2932·2019-08-29 14:00
閱讀 2407·2019-08-26 13:56
閱讀 426·2019-08-26 13:29
閱讀 1611·2019-08-26 11:31