R語言學習筆記之——數據處理神器data.table

2021-02-13 書圈

數據處理在數據分析流程中的地位相信大家都有目共睹,也是每一個數據從業者面臨的最為繁重的工作任務。

在實際應用場景下,雖然SQL(SQL類專業的etl語言)是數據處理的首選明星語言,性能佳、效率高、容易培養數據思維,但是SQL沒法處理構建全流程的數據任務,之後仍然需要藉助其他數據分析工具來對接更為深入的分析任務。

R語言作為專業的統計計算語言,數據處理是其一大特色功能,事實上每一個處理任務在R語言中都有著不止一套解決方案(這通常也是初學者在入門R語言時,感覺內容太多無從下手的原因),當然這些不同方案確實存在著性能和效率的絕大差異。

合理選擇一套自己的數據處理工具組合算是挺艱難的選擇,因為這個涉及到使用習慣和遷移成本的問題,比如你先熟知了R語言的基礎繪圖系統,在沒有強大的驅動力的情況下,你可能不太願意畫大把時間去研究ggplot2,你用會寫for/while循環,就不太願意去掌握apply組函數,甚至那些性能逆天的並行算運算包;剛開始會用基礎字符串處理,看到stringr包就面臨著技能工具更新的問題……

太多的選擇,讓人眼花繚亂,我自己也遇到過這種困惑,為了避免注意力分散,我的做法是先做可能性羅列——羅列一個可以實現同類功能的所有工具清單並做一套功能卡(也算是初步了解)。然後根據自己掌握的現狀選擇最熟練的一套,隨著時間的推移慢慢發現現有工具組合的不足,開始嘗試往更加高效、簡介的工具遷移,這樣以需求為推動力的技能升級和遷移更為徹底和明確。

最典型的幾個技能組合遷移如下:

基礎字符串處理函數——stringr繪圖系統:plot——ggplot2代碼風格:函數嵌套——管道函數(`%>%`)列表處理:list(自建循環)——rlistjson處理:Rjson+RJSONIO——jsonlite數據抓取:RCurl+XML——httr+xml2循環任務:for/while——apply——plyr::a_ply——並行運算(foreach、parallel)切片索引:subset——dplyr::select+filter聚合運算:aggregate——plyr::ddply+mutate——dplyr::group_by+summarize數據聯結:merge——plyr::join——dplyr::left/right/inner/outer_join數據塑型:plyr::melt/dcast——tidyr::gather/spread

……

其實還有很多類型的同類功能組合技能升級的路徑,不一給出,雖然工具遷移確實面臨著很高昂的代價,特別是時間成本、學習成本,但是遷移之後獲得的高效、代碼簡潔的體驗還是很爽的,以上特別是管道函數的遷移感觸最深,再也不存在自己寫完的東西間歇性懵逼的場景了。

說了這麼多,繞了這麼大的彎子想幹啥呢,沒錯今天又要給自己升級新技能啦,這次的主角兒是

data.table

一個R語言高性能數據處理包,一個包可以涵蓋以上所說的數據處理的大部分內容,而且操作高度抽象化話(抽象化就意味著代碼量少的可怕)。

其實很早就接觸過data.table,之所以一直沒有深入應用,因為它的理念與其他數據處理包偏離太遠,可以說遷移成本很高,幾乎就是技能重構而非遷移。

不過隨著視野的開闊,發現確實有必要深入了解這個高性能包,儘管有點兒顛覆R的傳統風格,但是性能和效率的提升可以彌補這一點。

data.table

1、I/O性能:

data.table的被推崇的重要原因就是他的IO吞吐性能在R語言諸多包中首屈一指,這裡以一個1.6G多的2015年紐約自行車出行數據集為例來檢驗其性能到底如何,希望我的小米本能扛得住折騰~_~

#清空內存
rm(list=ls())gc()

#使用傳統的I/O函數read_csv2進行導入:
setwd("D:/Python/citibike-tripdata/")system.time(     mydata1 <- read.csv("2015-citibike-tripdata.csv",stringsAsFactors = FALSE,check.names = FALSE)     )  用戶   系統   流逝 197.34   2.56 200.75
object.size(mydata1)
1914019808 bytes數據量還是很大的,將近1.6G,900多萬記錄,16個欄位。

可憐的機器呀,內存和磁碟要撐爆了~

使用data.table內的I/O函數進行導入:

rm(list=ls())gc()

library("data.table")system.time(     mydata1 <- fread("2015-citibike-tripdata.csv")     )Read 9937969 rows and 16 (of 16) columns from 1.606 GB file in 00:00:45 用戶  系統  流逝 43.44  0.48 44.43

五倍效率,45秒鐘900萬1.606G的數據,還是很有說服力的(雖然沒有傳說中的十倍性能)。

rm(list=ls())gc()

2、索引切片聚合

data.table中提供了將行索引、列切片、分組功能於一體的數據處理模型。

DT[i,j,by]

如果這個過程是SQL中是由select …… from …… where …… groupby …… having 來完成的,在R的其他基礎包中起碼也是分批次完成的。

dplyr::fliter() %>% select() %>% group_by() %>% summarize()

雖然可以藉助管道函數進行代碼優化,但是仍然無法與data.table的簡潔想抗衡。

mydata <- fread("https://raw.githubusercontent.com/wiki/arunsrinivasan/flights/NYCflights14/flights14.csv")

這裡使用一個在線數據集,包含2014年紐約機場發出的所有航班信息。

class(mydata)[1] "data.table" "data.frame"

使用fread函數導入之後便會自動轉化為data.table對象,這是data.table所特有的高性能數據對象,同時繼承了data.frame傳統數據框類,也意味著他能囊括很多數據框的方法和函數調用。

str(mydata)一共253316條記錄,17個欄位。

「year」      航班日期——年
「month」     航班日期——月
「day」       航班日期——天
「dep_time」  航班起飛時間
「dep_delay」 航班延誤時長
「arr_time」  航班到達時間
「arr_delay」 航班到達延誤時間
「cancelled」 航班是否取消
「carrier」
「tailnum」
「flight」
「origin」    起飛地
「dest」      目的地
「air_time」
「distance」  距離
「hour」
「min」

data.table行索引

carrier <- unique(mydata$carrier)[1] "AA" "AS" "B6" "DL" "EV" "F9" "FL" "HA" "MQ" "VX" "WN" "UA" "US" "OO"

tailnum <- sample(unique(mydata$tailnum),5)[1] "N332AA" "N813MQ" "N3742C" "N926EV" "N607SW"

origin  <- unique(mydata$origin)[1] "JFK" "LGA" "EWR"

dest    <- sample(unique(mydata$dest),5)[1] "BWI" "OAK" "DAL" "ATL" "ALB"``mydata[carrier == "AA" ]#等價於mydata[carrier == "AA",]#行索引可以直接引用列表,無需加表明前綴,這一點兒數據框做不到,而且i,j,by三個參數對應的條件支持模糊識別,無論加「,」與否都可以返回正確結果。mydata[carrier %in% c("AA","AS"),]支持在行索引位置使用%in% 函數。

data.table列索引

列索引與數據框相比操作體驗差異比較大,data.table的列索引摒棄了data.frame時代的向量化參數,而使用list參數進行列索引。

mydata[,list(carrier,tailnum)]

為了操作體驗更佳,這裡的list可以簡化為一個英文句點符號。即:

mydata[,.(carrier,tailnum)]
#但心裡要清楚列索引接受的條件是含有列表的列表,而且這裡的列表作為變量給出,而非data.frame時代的字符串向量。

行列同時索引毫無壓力。

mydata[carrier %in% c("AA","AS"),.(carrier,tailnum)]

列索引的位置不僅支持列名索引,可以直接支持內建函數操作。

mydata[,.(flight/1000,carrier,tailnum)]

支持直接在列索引位置新建列,賦值符號為:=。

mydata[,delay_all := dep_delay+arr_delay]
#銷毀某一列:
mydata[,delay_all := NULL]

批量新建列:

mydata[,c("delay_all","delay_dif") := .((dep_delay+arr_delay),(dep_delay-arr_delay))]等價於寫法2:mydata[,`:=`(delay_all = dep_delay+arr_delay,delay_dif =dep_delay-arr_delay )]
#銷毀新建列:
mydata[,c("delay_all","delay_dif") := NULL]


注意以上新建列時,如果只有一列,列名比較自由,寫成字符串或者變量都可以,但是新建多列,必須嚴格按照左側列名為字符串向量,右側為列表的模式,當然你也可以使用第二種寫法。

DT[,`:=`(varname1 = statement1 ,varname1 = statement2)]

可以直接使用data.table內建的函數。

mydata[carrier %in% c("AA","AS"),.N][1] 26876
.N是一個計數函數,相當於plyr中的count,或者基礎函數中的length。

基本的統計函數都可以直接支持。

mydata[carrier %in% c("AA","AS"),.(sum(dep_delay),mean(arr_delay))]       V1       V2
1: 228913 5.263841

mydata[carrier %in% c("AA","AS"),.(dep_delay,mean(arr_delay))]mydata[carrier %in% c("AA","AS") & dep_delay %between% c(500,1000),.(dep_delay,arr_delay)]

當整列和聚合的單值同時輸出時,可以支持自動補齊操作。

當聚合函數與data.table中的分組參數一起使用時,data.table的真正威力才逐漸顯露。

mydata[,.(sum(dep_delay),mean(arr_delay)),by = carrier]

多分組聚合。

mydata[,.(sum(dep_delay),mean(arr_delay)),by = .(carrier,origin)]

多分組計數。

mydata[,.N,by = .(carrier,origin)]

自定義名稱:

mydata[,.(dep_delay_sum = sum(dep_delay),arr_delay_mean = mean(arr_delay)),by = carrier]mydata[,.(dep_delay_sum = sum(dep_delay),arr_delay_mean = mean(arr_delay)),by = .(carrier,origin)]mydata[,.(carrier_n = .N),by = .(carrier,origin)]


數據排序:

排序行:

setorder(mydata,carrier,-arr_delay)

setorder函數作用於mydata本身,運行無輸出。如果想要運行的同時進行輸出則可以在結尾加上[]

setorder(mydata,carrier,-arr_delay)[]

這個功能有點兒類似於基礎函數中,在語句外部加上圓括號。(a <- 1+1)

排序列:

sample(names(mydata),length(names(mydata))) [1] "arr_time"  "air_time"  "distance"  "dep_time"  "dest"      "arr_delay" "month"     "min"       "tailnum"   "origin"  
[11] "year"      "hour"      "cancelled" "flight"    "day"       "carrier"   "dep_delay"

setcolorder(mydata,sample(names(mydata),length(names(mydata))))mydata[carrier == "AA",        lapply(.SD, mean),        by=.(carrier,origin,dest),        .SDcols=c("arr_delay","dep_delay")        ]

以上語法加入了新的參數.SDcols和.SD,咋一看摸不著頭腦,其實是在按照carrier,origin,dest三個維度分組的基礎上,對每個子塊特定列進行均值運算。

這裡的執行邏輯是這樣的:

by=.(carrier,origin,dest) 先按照三個維度進行全部的分組;.SDcols=c("arr_delay","dep_delay")則分別在篩選每一個子數據塊兒上的特定列;lapply(.SD, mean)則將各個子塊的對應列應用於均值運算,並返回最終的列表。

數據合併:

data.table的數據合併方式非常簡潔;

DT <- data.table(x=rep(letters[1:5],each=3), y=runif(15))DX <- data.table(z=letters[1:3], c=runif(3))

設置各自的主鍵:

setkey(DT,x)setkey(DX,z)DT[DX]

就是如此簡單,連接的執行邏輯是,內側是左表,外側是右表,所以是DX left join DT

如果沒有設置主鍵,需要顯式聲明內部的on參數,指定連接主鍵,單主鍵必須在左右表中名稱一致。

當然你要是特別不習慣這種用法,還是習慣使用merge的話,data.table仍然是支持的,因為他本來就繼承了數據框,支持所有針對數據框的函數調用。

本文轉自:數據小魔方

-END-

圖文來自網絡、如涉及版權問題,請聯繫我們以便處理。文章內容純屬作者個人觀點,不代表本網觀點。

相關焦點

  • R語言-data.table-數據處理
    data.table 包數據處理data.table 包數據處理前言基礎介紹基本格式i j by 使用讀取數據行篩選列篩選總結
  • R語言數據分析利器——data.table包
    簡介R語言data.table包是自帶包data.frame的升級版
  • R數據處理|data.table篇(三)
    本文為data.table包介紹最後一篇,前兩篇連結如下R數據處理|data.table篇(一) - 知乎專欄R數據處理|data.table篇(二) - 知乎專欄本文主要講解data.table包中一些比較不常用的函數,還有data.table包高效的深層原理。
  • R數據處理|data.table篇(一)
    data.table包是一個超高性能處理包,在數據處理上代碼異常簡潔,速度非常快。由於data.table的語法主要基於[],有些用法和基礎函數會不一致,所以沒有放在前面兩個專題中一起講,而是單獨拿出來講。在這個系列裡,我會詳細說明data.table和基礎函的差異,並系統地講解data.table包的用法。
  • data.table包R包
    如何學習?如何應用?如同三把斧,擺在每位學R和用R的數據人面前,如何輕鬆自如揮舞,仁者見仁、智者見智!」從今天開始,陸續推出一系列關於好用的R包的文章,歡迎各位數據人反饋、留言、投稿。data.table包是對R語言數據框Data.frame的擴展和延伸。data.table要做的事情?
  • R語言:data.table語句批量生成變量
    ,在data.table包和MongoDB的使用上有較多經驗。關於 ':= lapply' 的用法,在這裡小編不再贅述,如果大家對此不是很熟悉可以看這一期公眾號:用data.table語句批量處理變量。在這裡通過連結中的推送的lapply使用原理,再加上stringr包中str_match這個函數的使用,截取出診斷結果中出現過的繼發性醛固酮或者醛固酮,沒有出現過的自動記為NA。
  • R語言學習筆記(2)數據處理和基本繪圖
    上節匯總了R語言的基本數據結構以及如何查看數據類型,本期我們將接著學習R中常見的數據處理操作和一些R基本繪圖功能。
  • 【R學習筆記】- 數據整形 - dplyr and tidyr
    此外data.table包也有reshape2包類似的功能。今天這兩個包是同一個人寫的,他還開發ggplot2包,前面用來導入spass數據的haven包也是他的作品。,類似標準函數ordersummarise() 對數據進行匯總操作,可結合group_by使用,類似標註函數aggregatejoin(),set(),distinct(),sample(),bind(),ifelse()參考資料數據整合神器之tidyr包 數據整合神器之dplyr包 Data Wrangling with dplyr
  • R語言中的Pandas:50題搞定 data.table
    R語言:50題搞定 data.table 簡介 data.table 是 R 語言中用於處理表格數據的包,相當於 Python 語言的 pandas,是學習 R 語言數據分析與挖掘必備工具。接下來我們用 50 道題學習data.table 的各種技巧。
  • R語言-stringr-字符串處理
    R包stringr處理字符相對簡單,尤其是我常用Power BI,但是對M語言不熟悉,不會處理字符數據,往往我就先利用R清洗字符數據列。本文記錄工作中常用的字符處理函數,部分案例照搬R for Data Science的字符部分。
  • R 語言入門學習路線與資源匯總
    4.1 文本文件文本格式文件可以使用utils包的read.table()[23]函數和read.csv()[24]函數導入,還有readr[25]包和data.table包的fread()[26]函數也可以快速導入數據。
  • R語言data manipulation學習筆記之subset data
    taoyan:R語言中文社區特約作家,偽碼農,R語言愛好者,愛開源。
  • R語言數據導入之read.table
    , $,%, ^, &, *, (, ),-,#, ?,,,<,>, /, |, , [ ,] ,{, };如果使用excel表,應刪除多餘的列或者是注釋一類的內容確保缺失數據標記為空準備工作空間可以參考使用Rsudio這類的編輯器,為了確保工作空間中沒有已有的對象對當前的操作有影響,需要清空內存對象。
  • 【萬字長文】R語言入門學習路線與資源匯總
    4.1 文本文件文本格式文件可以使用utils包的read.table()[23]函數和read.csv()[24]函數導入,還有readr[25]包和data.table包的fread()[26]函數也可以快速導入數據。
  • R|數據處理|list的轉化與轉置
    (a=ay, b=bz))beforeafter# 實現將 before 轉換成after形式,其實就是對列表進行轉置# 另外一個例子,list 中的元素是向量而不是listl <- list(1:4,1:4)下面使用幾種方法實現# 第一種方法,使用 data.table 和 purrr 包中現成的函數# data.table::transpose
  • R代碼|data.table包使用示例
    ##################################時間:2020-07-29################################options(warn = -1)# 加載data.table包library(data.table)# 數據導入
  • 關注 | R語言從入門到精通:Day4-R語言數據導入測試代碼及數據
    這些數據類型在我們運用R語言解決實際問題的時候都非常有用,在上節的例子中我們是在R裡面直接生成的數據,但是實際數據分析中,如何快速靈活的讀取和處理多種格式的外部數據呢?這節課的主要內容,我們就來講講R語言中數據的讀取。1、本節內容重點內容較多,      務必緊跟紅色標記。2、測試數據及代碼      見文末客服小姐姐二維碼。
  • 【好書共享】《R for Data Science》的中譯版
    這本書原版就是開源的(網址:http://r4ds.had.co.nz/),但是中文看得更快,學R語言一定要買一本紙質書放在案頭,多多翻閱。R for Data Science關於這本書這本書將教我們如何用R來做數據科學:學習如何將自己的數據導入R中,把它變成最有用的結構,轉換,可視化並對數據進行建模。
  • R語言-初識與數據結構
    S語言:1976年貝爾實驗室發展起來的數據交互分析系統;是一種高級程序語言,很好地統計應用快速開發系統。關於S語言更多信息見:http://cm.bell-labs.com/cm/ms/departments/sia/S/history.htmlScheme語言:Scheme 語言是計算機表面處理語言,該語言用於處理包含有表格的數據的程式語言,被廣泛地運用於人工智慧研究。
  • R語言數據清洗實戰——高效list解析方案
    好在確實有開發者在針對list數據結構進行操作上的優化,任坤老師的大作——rlist就是一個強大的list解析神器,它可以讓我們像在dplyr、data.table操作data.frame一樣,使用rlist輕鬆的實現對list數據類型的map(映射)、filter(篩選)、update(更新)、group(分組)、sort(排序)。