如今有 100500 門數據科學課程,人們早就知道數據科學領域的大部分錢可以透過數據科學課程賺到(當你可以賣鐵鍬時為什麼要挖坑呢?)。 這些課程的主要缺點是它們與實際工作無關:沒有人會給你所需格式的乾淨的、經過處理的數據。 當您離開課程並開始解決實際問題時,會出現許多細微差別。
因此,我們根據發生在我、我的同志和同事身上的真實事件,開始了一系列筆記「數據科學可能會出什麼問題」。 我們將使用真實的例子來分析典型的資料科學任務:這實際上是如何發生的。 讓我們從今天的資料收集任務開始。
當人們開始使用真實數據時,他們遇到的第一件事實際上是收集與我們最相關的數據。 本文的關鍵訊息:
我們系統性地低估了收集、清理和準備資料所需的時間、資源和精力。
最重要的是,我們將討論如何防止這種情況發生。
根據各種估計,清理、轉換、資料處理、特徵工程等佔了 80-90% 的時間,分析佔據了 10-20% 的時間,而幾乎所有的教育材料都只專注於分析。
我們以一個簡單的三個版本的分析問題為例,看看什麼是「情節嚴重」。
再次舉個例子,我們將考慮收集數據和比較社區的任務的類似變化:
- 兩個 Reddit 子版塊
- 哈布爾的兩個部分
- 兩組 Odnoklassniki
理論上的條件方法
打開網站並閱讀範例,如果清楚,請留出幾個小時用於閱讀,幾個小時用於使用範例的程式碼和調試。 增加幾個小時的收集時間。 預留幾個小時(乘以 XNUMX 並加上 N 小時)。
重點:時間估計是基於對需要多長時間的假設和猜測。
有必要透過估計上述條件問題的以下參數來開始時間分析:
- 資料的大小是多少以及需要實體收集多少資料(*見下文*)。
- 一筆記錄的收集時間是多少?您需要等待多久才能收集第二筆記錄?
- 考慮編寫程式碼來保存狀態並在(而不是如果)一切都失敗時啟動重新啟動。
- 弄清楚我們是否需要授權並設定透過API取得存取權的時間。
- 將錯誤數量設定為資料複雜性的函數 - 評估特定任務:結構、轉換次數、擷取內容和方式。
- 修復網路錯誤和非標準項目行為問題。
- 評估所需的功能是否在文件中,如果沒有,則需要如何以及需要多少解決方法。
最重要的是,為了估算時間——你實際上需要花時間和精力進行「強力偵察」——只有這樣你的計劃才算充分。 因此,無論你多麼被迫說“收集數據需要多長時間”,都要為自己爭取一些時間進行初步分析,並根據問題的實際參數來討論時間會變化多少。
現在我們將示範這些參數將發生變化的具體範例。
重點:估算是基於影響工作範圍和複雜性的關鍵因素的分析。
當功能元素足夠小且沒有太多因素可以顯著影響問題的設計時,基於猜測的估計是一種很好的方法。 但在許多數據科學問題的情況下,這類因素變得極為眾多,而這種方法就變得不夠充分。
Reddit 社群比較
讓我們從最簡單的情況開始(稍後會證明)。 一般來說,說實話,我們有一個幾乎理想的情況,讓我們檢查一下我們的複雜性清單:
- 有一個整潔、清晰且有文件記錄的 API。
- 非常簡單,最重要的是,令牌是自動獲得的。
- 有
蟒蛇包裝器 - 有很多例子。 - 一個在 reddit 上分析和收集資料的社群(甚至是解釋如何使用 python 包裝器的 YouTube 影片)
例如 . - 我們需要的方法很可能存在於 API 中。 此外,程式碼看起來緊湊而乾淨,下面是一個收集帖子評論的函數範例。
def get_comments(submission_id):
reddit = Reddit(check_for_updates=False, user_agent=AGENT)
submission = reddit.submission(id=submission_id)
more_comments = submission.comments.replace_more()
if more_comments:
skipped_comments = sum(x.count for x in more_comments)
logger.debug('Skipped %d MoreComments (%d comments)',
len(more_comments), skipped_comments)
return submission.comments.list()
取自
儘管這是最好的情況,但仍然值得考慮現實生活中的一些重要因素:
- API 限制 - 我們被迫大量取得資料(在請求之間休眠等)。
- 收集時間 - 為了進行完整的分析和比較,您必須留出大量時間讓蜘蛛瀏覽 subreddit。
- 機器人必須在伺服器上運行——你不能只在筆記型電腦上運行它,把它放在背包裡,然後繼續你的業務。 所以我在 VPS 上運行一切。 使用促銷代碼 habrahabr10 您還可以節省 10% 的費用。
- 某些資料的實體無法存取性(管理員可見或太難收集)-必須考慮到這一點;原則上,並非所有資料都可以在足夠的時間內收集。
- 網路錯誤:網路是一種痛苦。
- 這是活生生的真實數據——它從來都不是純粹的。
當然,在開發過程中需要考慮到這些細微差別。 特定的時間/天數取決於開發經驗或從事類似任務的經驗,但是,我們看到這裡的任務純粹是工程性的,不需要額外的身體動作來解決——一切都可以很好地評估、安排和完成。
哈布爾剖面比較
讓我們繼續討論一個更有趣且不平凡的案例,比較 Habr 的線程和/或部分。
讓我們檢查一下我們的複雜性清單 - 在這裡,為了理解每一點,您必須深入研究任務本身並進行實驗。
- 起初你以為有 API,但實際上並沒有。 是的,是的,Habr 有一個 API,但使用者無法存取它(或者可能根本不起作用)。
- 然後你就開始解析 html - “導入請求”,會出現什麼問題?
- 無論如何如何解析? 最簡單和最常用的方法是迭代 ID,請注意,這不是最有效的,必須處理不同的情況 - 這是所有現有 ID 中真實 ID 密度的範例。
取自此 文章。 - 在 Web 上將原始資料封裝在 HTML 中是一件痛苦的事。 例如,您想要收集並保存一篇文章的評分:您從 html 中取出評分並決定將其儲存為數字以供進一步處理:
1) int(score) 拋出一個錯誤:因為在Habré 上有一個減號,例如,在“–5”行中- 這是一個破折號,而不是減號(出乎意料,對吧?),所以在某種程度上,我不得不透過如此糟糕的修復來提高解析器的生命力。
try: score_txt = post.find(class_="score").text.replace(u"–","-").replace(u"+","+") score = int(score_txt) if check_date(date): post_score += score
可能根本沒有日期、優點和缺點(正如我們在上面的 check_date 函數中看到的那樣,這種情況發生了)。
2)未轉義的特殊字元-它們會出現,你需要做好準備。
3) 結構依職位類型而變化。
4)舊貼文可能有**奇怪的結構**。
- 從本質上講,錯誤處理以及可能發生或不發生的事情都必須處理,並且您無法確定會出現什麼問題,結構可能會如何以及什麼會在哪裡脫落 - 您只需要嘗試並考慮解析器拋出的錯誤。
- 然後你意識到你需要在多個線程中進行解析,否則在一個線程中進行解析將需要30 多個小時(這純粹是已經工作的單線程解析器的執行時間,它會休眠並且不會受到任何禁令的影響)。 在
此 文章中,這在某種程度上導致了類似的方案:
依複雜程度列出的總清單:
- 使用網路和 html 解析進行迭代並按 ID 進行搜尋。
- 異構結構的文檔。
- 有很多地方代碼很容易出錯。
- 必須寫|| 代碼。
- 缺少必要的文件、程式碼範例和/或社群。
此任務的預計時間將比從 Reddit 收集數據高 3-5 倍。
Odnoklassniki 組的比較
讓我們繼續討論所描述的技術上最有趣的案例。 對我來說,這很有趣,因為乍一看,它看起來很微不足道,但一旦你用棍子戳它,你會發現它根本不是那樣的。
讓我們從難度清單開始,請注意,其中許多問題會比最初看起來困難得多:
- 有一個API,但幾乎完全缺乏必要的功能。
- 對於某些功能,您需要透過郵件請求存取權限,也就是說,存取權限的授予不是即時的。
- 它的記錄非常糟糕(首先,俄語和英語術語到處都是混合的,而且完全不一致——有時你只需要猜測他們想從你那裡得到什麼),而且,該設計不適合獲取數據,例如,
我們需要的功能 . - 需要文件中的會話,但實際上並沒有使用它 - 除了四處探索並希望某些東西能夠工作之外,沒有辦法理解 API 模式的所有複雜性。
- 沒有例子,也沒有社區;收集資訊的唯一支持點是一個小的
包裝紙 在Python中(沒有很多使用範例)。 - Selenium 似乎是最可行的選擇,因為許多必要的數據都被鎖定了。
1) 即透過虛構使用者進行授權(並手動註冊)。2)但是,使用 Selenium 並不能保證正確且可重複的工作(至少在 ok.ru 的情況下是肯定的)。
3) Ok.ru 網站包含 JavaScript 錯誤,有時表現奇怪且不一致。
4)你需要做分頁,載入元素等......
5)包裝器給出的API錯誤將不得不笨拙地處理,例如,像這樣(一段實驗代碼):
def get_comments(args, context, discussions): pause = 1 if args.extract_comments: all_comments = set() #makes sense to keep track of already processed discussions for discussion in tqdm(discussions): try: comments = get_comments_from_discussion_via_api(context, discussion) except odnoklassniki.api.OdnoklassnikiError as e: if "NOT_FOUND" in str(e): comments = set() else: print(e) bp() pass all_comments |= comments time.sleep(pause) return all_comments
我最喜歡的錯誤是:
OdnoklassnikiError("Error(code: 'None', description: 'HTTP error', method: 'discussions.getComments', params: …)”)
6)最終,Selenium + API 看起來是最合理的選擇。
- 有必要保存狀態並重新啟動系統,處理許多錯誤,包括網站的不一致行為 - 這些錯誤非常難以想像(當然,除非您專業地編寫解析器)。
此任務的條件時間估計將比從 Habr 收集資料高 3-5 倍。 儘管事實上,在 Habr 的情況下,我們使用了 HTML 解析的前端方法,並且在 OK 的情況下,我們可以在關鍵位置使用 API。
發現
無論您需要多少時間來「現場」估計大量資料處理管道模組的最後期限(我們今天正在計劃!),如果不分析任務參數,執行時間幾乎永遠不可能定性估計。
從更哲學的角度來說,敏捷估算策略對於工程任務來說效果很好,但是更具實驗性的問題,從某種意義上來說,「創造性」和探索性的問題,即不太可預測的問題,會遇到困難,就像類似主題的例子一樣,我們已經在這裡討論過。
當然,資料收集只是一個典型的例子 - 它通常是一項非常簡單且技術上並不複雜的任務,而問題往往在於細節。 正是在這項任務中,我們可以展示可能出現問題的所有可能選項以及工作需要多長時間。
如果你在沒有額外實驗的情況下看一下任務的特徵,那麼 Reddit 和 OK 看起來很相似:有一個 API,一個 python 包裝器,但本質上,差異是巨大的。 從這些參數來看,Habr 的 pars 看起來比 OK 更複雜——但實際上恰恰相反,這正是透過簡單的實驗來分析問題的參數所能發現的。
根據我的經驗,最有效的方法是粗略估計初步分析本身和簡單的第一次實驗所需的時間,閱讀文件 - 這些將使您能夠對整個工作做出準確的估計。 按照流行的敏捷方法論,我要求你創建一個「估算任務參數」的工單,在此基礎上我可以評估「衝刺」內可以完成的工作,並對每個任務給出更準確的估算任務。
因此,最有效的論點似乎是向「非技術」專家展示多少時間和資源將根據尚未評估的參數而變化。
來源: www.habr.com