R數(shù)據(jù)科學(xué)chapter8

library(tidyverse)

#使用readr進(jìn)行數(shù)據(jù)導(dǎo)入

#? read_csv() 讀取逗號(hào)分隔文件狡孔、

#read_csv2() 讀取分號(hào)分隔文件(這在用 , 表示小數(shù)位的國(guó)家非常普遍)讯泣、

#read_tsv() 讀取制表符分隔文件、

#read_delim() 可以讀取使用任意分隔符的文件矿辽。

#? read_fwf() 讀取固定寬度的文件竞膳。

#既可以使用 fwf_widths() 函數(shù)按照寬度來設(shè)定域渗钉,也可以使用fwf_positions() 函數(shù)按照位置來設(shè)定域彤恶。

#read_table() 讀取固定寬度文件的一種常用變體钞钙,其中使用空白字符來分隔各列。

#? read_log() 讀取 Apache 風(fēng)格的日志文件声离。(但需要檢查是否安裝了 webreadr 包芒炼,https:// github.com/Ironholds/webreadr,因?yàn)樵摪挥?read_log() 函數(shù)的開頭术徊,還可以提供很多 有用的工具本刽。)

#read_csv() 函數(shù)的第一個(gè)參數(shù)是最重要的,該參數(shù)是要讀取的文件的路徑

#當(dāng)運(yùn)行read_csv() 時(shí)赠涮,它會(huì)打印一份數(shù)據(jù)列說明子寓,給出每個(gè)列的名稱和類型。

read_csv("a,b,c

1,2,3

4,5,6")

#read_csv() 函數(shù)都使用數(shù)據(jù)的第一行作為列名稱笋除,這是一種常見做法斜友。

#? 有時(shí)文件開頭會(huì)有好幾行元數(shù)據(jù)。你可以使用skip = n來跳過前n行;或者使用 comment = "#" 來丟棄所有以 # 開頭的行:

read_csv("The first line of metadata

? ? ? The second line of metadata

? ? ? x,y,z

? ? ? 1,2,3", skip = 2)

read_csv("# A comment I want to skip

? ? ? x,y,z

? ? ? 1,2,3", comment = "#")

#? 數(shù)據(jù)沒有列名稱垃它∠势粒可以使用col_names = FALSE來通知read_csv()不要將第一行作為列標(biāo)題,而是將各列依次標(biāo)注為 X1 至 Xn:

read_csv("1,2,3\n4,5,6", col_names = FALSE)

#"\n" 是非常便捷的快捷方式国拇,用于添加新行

#你也可以向 col_names 傳遞一個(gè)字符向量墙歪,以用作列名稱

read_csv("1,2,3\n4,5,6", col_names = c("x", "y", "z"))

#另一個(gè)通常需要修改的選項(xiàng)是 na。它設(shè)定使用哪個(gè)值(或哪些值)來表示文件中的缺失值:

read_csv("a,b,c\n1,2,.", na = ".")

#你肯定很想知道我們?yōu)槭裁床皇褂?read.csv() 函數(shù)

#? 一般來說贝奇,它們比基礎(chǔ)模塊中的函數(shù)速度更快(約快 10 倍)。

#? 它們可以生成 tibble靠胜,并且不會(huì)將字符向量轉(zhuǎn)換為因子掉瞳,不使用行名稱,也不會(huì)隨意改動(dòng)列名稱浪漠。

#? 它們更易于重復(fù)使用陕习。

#解析向量

#parse_*() 函數(shù)族。

#這些函數(shù)接受一個(gè)字符向量址愿,并返回一個(gè)特定向量该镣,如邏輯、整數(shù)或日期向量:

str(parse_logical(c("TRUE", "FALSE", "NA")))

#> logi [1:3] TRUE FALSE NA

str(parse_integer(c("1", "2", "3")))

#> int [1:3] 1 2 3

str(parse_date(c("2010-01-01", "1979-10-14")))

#> Date[1:2], format: "2010-01-01" "1979-10-14"

#第一個(gè)參數(shù)是需要解析的字符向量响谓,

#na 參數(shù)設(shè)定了哪些字符串應(yīng)該當(dāng)作缺失值來處理

parse_integer(c("1", "231", ".", "456"), na = ".")

#> [1] 1 231 NA 456

#如果解析失敗损合,你會(huì)收到一條警告:

? x <- parse_integer(c("123", "345", "abc", "123.45"))

#> Warning: 2 parsing failures.

#> row col expected actual

#解析失敗的值在輸出中是以缺失值的形式存在的

? x

#如果解析失敗的值很多,那么就應(yīng)該使用 problems() 函數(shù)來獲取完整的失敗信息集合娘纷。

#這個(gè)函數(shù)會(huì)返回一個(gè) tibble嫁审,你可以使用 dplyr 包來進(jìn)行處理

? problems(x)

#在解析函數(shù)的使用方面,最重要的是要知道有哪些解析函數(shù)赖晶,

#以及每種解析函數(shù)用來處理 哪種類型的輸入律适。

#具體來說,重要的解析函數(shù)有 8 種。

#? parse_logical() 和 parse_integer() 函數(shù)分別解析邏輯值和整數(shù)捂贿。因?yàn)檫@兩個(gè)解析函數(shù)基本不會(huì)出現(xiàn)問題纠修,所以我們不再進(jìn)行更多介紹。

#? parse_double() 是嚴(yán)格的數(shù)值型解析函數(shù)厂僧,parse_number() 則是靈活的數(shù)值型解析函數(shù)扣草。 這兩個(gè)函數(shù)要比你預(yù)想的更復(fù)雜,因?yàn)槭澜绺鞯貢鴮憯?shù)值的方式不盡相同吁系。

#? parse_character() 函數(shù)似乎太過簡(jiǎn)單德召,甚至沒必要存在。但一個(gè)棘手的問題使得這個(gè)函數(shù)變得非常重要:字符編碼汽纤。

#? parse_factor() 函數(shù)可以創(chuàng)建因子上岗,R 使用這種數(shù)據(jù)結(jié)構(gòu)來表示分類變量,該變量具有固定數(shù)目的已知值蕴坪。

#? parse_datetime()肴掷、parse_date() 和 parse_time() 函數(shù)可以解析不同類型的日期和時(shí)間。 它們是最復(fù)雜的背传,因?yàn)橛刑嗖煌娜掌跁鴮懶问健?/p>

#數(shù)值

#? 世界各地的人們書寫數(shù)值的方式不盡相同呆瞻。例如,有些國(guó)家使用 . 來分隔實(shí)數(shù)中的整數(shù) 和小數(shù)部分径玖,而有些國(guó)家則使用 ,痴脾。

#? 數(shù)值周圍經(jīng)常有表示某種意義的其他字符,如 $1000 或 10%梳星。

#? 數(shù)值經(jīng)常包含“分組”赞赖,以便更易讀,如 1 000 000冤灾,而且世界各地用來分組的字符也不盡相同前域。

#readr 使用了“地區(qū)”這一概念,這是可以按照不同地區(qū)設(shè)置解析選項(xiàng)的一個(gè)對(duì)象韵吨。

#在解析數(shù)值時(shí)匿垄,最重要的選項(xiàng)就是用來表示小數(shù)點(diǎn)的字符。

#通過創(chuàng)建一個(gè)新的地區(qū)對(duì)象并設(shè)定 decimal_mark 參數(shù)归粉,可以覆蓋 . 的默認(rèn)值

parse_double("1.23")

parse_double("1,23", locale = locale(decimal_mark = ","))

#readr 的默認(rèn)地區(qū)是 US-centric椿疗,因?yàn)?R 是以美國(guó)為中心的(也就是說,R 基礎(chǔ)包的文檔是用美式英語寫成的)盏浇。

#parse_number() 解決了第二個(gè)問題:它可以忽略數(shù)值前后的非數(shù)值型字符变丧。

#這個(gè)函數(shù)特別適合處理貨幣和百分比,也可以提取嵌在文本中的數(shù)值:

parse_number("$100")

#> [1] 100

parse_number("20%")

#> [1] 20

parse_number("It cost $123.45")

#> [1] 123

#組合使用 parse_number() 和地區(qū)設(shè)置可以解決最后一個(gè)問題绢掰,因?yàn)?parse_number() 可以忽略“分組符號(hào)”:

# 適用于美國(guó)

parse_number("$123,456,789")

#> [1] 1.23e+08

# 適用于多數(shù)歐洲國(guó)家

parse_number(

"123.456.789",

locale = locale(grouping_mark = ".")

)

#> [1] 1.23e+08

# 適用于瑞士

parse_number(

"123'456'789",

locale = locale(grouping_mark = "'")

)

#> [1] 1.23e+08

#字符串

#parse_character() 函數(shù)似乎真的很簡(jiǎn)單痒蓬,只要返回輸入值就可以了童擎。

#問題是生活沒這么簡(jiǎn)單,因?yàn)橥粋€(gè)字符串有多種表示方式攻晒。

#在 R 中顾复,我們可以使用 charToRaw() 函數(shù)獲得一個(gè)字符串的底層表示

charToRaw("Hadley")

#> [1] 48 61 64 6c 65 79

#每個(gè)十六進(jìn)制數(shù)表示信息的一個(gè)字節(jié):48 是 H、61 是 a 等鲁捏。

#從十六進(jìn)制數(shù)到字符的這種映射稱為編碼芯砸,這個(gè)示例中的編碼方式稱為 ASCII。

#UTF-8 可以為現(xiàn)在人類使用的所有字符進(jìn)行編碼给梅,同時(shí)還支持很多特殊字符(如 表情符號(hào)!)

#readr 全面支持 UTF-8:當(dāng)讀取數(shù)據(jù)時(shí)假丧,它假設(shè)數(shù)據(jù)是 UTF-8 編碼的,并總是使用 UTF-8 編碼寫入數(shù)據(jù)动羽。

#但對(duì)于從不支持 UTF-8 的那些舊系統(tǒng)中產(chǎn)生的數(shù) 據(jù)則無能為力包帚。遇到這種情況時(shí),你的字符串打印出來就是一堆亂碼运吓。

x1 <- "El Ni\xf1o was particularly bad this year"

x2 <- "\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd"

#要想解決這個(gè)問題渴邦,需要在 parse_character() 函數(shù)中設(shè)定編碼方式:

? parse_character(x1, locale = locale(encoding = "Latin1"))

#> [1] "El Ni?o was particularly bad this year"

parse_character(x2, locale = locale(encoding = "Shift-JIS"))

#> [1] "こんにちは"

#如何才能找到正確的編碼方式呢?

#因此 readr 提供了 guess_encoding() 函數(shù)來幫助你找出編碼方式。

#希望試驗(yàn)幾次后拘哨,你就能夠找到正確的編碼方式:

guess_encoding(charToRaw(x1))

#> encoding confidence

#> 1 ISO-8859-1 0.46

#> 2 ISO-8859-9 0.23

guess_encoding(charToRaw(x2))

#> encoding confidence

#> 1? KOI8-R? ? ? 0.42

#guess_encoding() 的第一個(gè)參數(shù)可以是一個(gè)文件路徑谋梭,也可以是一個(gè)原始向量(適用于字 符串已經(jīng)在 R 中的情況),就像本示例一樣倦青。

#因子

#R 使用因子表示取值范圍是已知集合的分類變量瓮床。

#如果 parse_factor() 函數(shù)的 levels 參數(shù)被賦予一個(gè)已知向量,

#那么只要存在向量中沒有的值产镐,就會(huì)生成一條警告:

fruit <- c("apple", "banana")

parse_factor(c("apple", "banana", "bananana"), levels = fruit)

#日期纤垂、日期時(shí)間與時(shí)間

#根據(jù)需要的是日期型數(shù)據(jù)(從 1970-01-01 開始的天數(shù))、

#日期時(shí)間型數(shù)據(jù)(從 1970-01-01 午夜開始的秒數(shù))磷账,

#或者是時(shí)間型數(shù)據(jù)(從午夜開始的秒數(shù))

#? parse_datetime() 期待的是符合ISO 8601 標(biāo)準(zhǔn)的日期時(shí)間。

#ISO 8601 是一種國(guó)際標(biāo)準(zhǔn)贾虽, 其中日期的各個(gè)部分按從大到小的順序排列逃糟,即年、月蓬豁、日绰咽、小時(shí)、分鐘地粪、秒:

parse_datetime("2010-10-01T2010")

#> [1] "2010-10-01 20:10:00 UTC"

# 如果時(shí)間被省略了取募,那么它就會(huì)被設(shè)置為午夜

parse_datetime("20101010")

#> [1] "2010-10-10 UTC"

#這是最重要的日期 / 時(shí)間標(biāo)準(zhǔn)

#? parse_date() 期待的是四位數(shù)的年份、一個(gè) - 或 /蟆技、月玩敏、一個(gè) - 或 /斗忌,然后是日:

parse_date("2010-10-01")

#> [1] "2010-10-01"

#? parse_time() 期待的是小時(shí)、:旺聚、分鐘织阳、可選的 : 和秒,以及一個(gè)可選的 a.m./p.m. 標(biāo)識(shí)符:

library(hms)

parse_time("01:10 am")

#> 01:10:00

parse_time("20:10:01")

#> 20:10:01

#找出正確格式的最好方法是創(chuàng)建幾個(gè)解析字符向量的示例砰粹,并使用某種解析函數(shù)進(jìn)行測(cè)

試唧躲。例如:

? parse_date("01/02/15", "%m/%d/%y")

#> [1] "2015-01-02"

parse_date("01/02/15", "%d/%m/%y")

#> [1] "2015-02-01"

parse_date("01/02/15", "%y/%m/%d")

#> [1] "2001-02-15"

challenge <- read_csv(

? readr_example("challenge.csv"),

? col_types = cols(

? ? x = col_double(),

? ? y = col_date()

? )

)

tail(challenge)

#解析文件

#? readr 如何自動(dòng)猜出文件每列的數(shù)據(jù)類型。

#? 如何修改默認(rèn)設(shè)置碱璃。

#強(qiáng)烈建議你總是提供 col_types 參數(shù)弄痹,從 readr 打印出的輸出中可以知道它的值。

#這可以確保數(shù)據(jù)導(dǎo)入腳本的一致性嵌器,并可以重復(fù)使用肛真。

#這種方式結(jié)合 type_convert() 函數(shù)使用時(shí)特別有效,后者可以在數(shù)據(jù)框的字符列上應(yīng)用啟發(fā)式解析過程

df <- tribble(

? ~x,? ~y,

? "1", "1.21",

? "2", "2.32",

? "3", "4.56"

)

df

type_convert(df)

read_csv("x,y

? ? ? ? 1, 1.21,

? ? ? ? 2, 2.32,

? ? ? ? 3, 4.56",col_types = cols(

? ? ? ? ? x = col_integer(),

? ? ? ? ? y = col_double()))

#write_csv() 和 write_tsv()

#? 它們總是使用 UTF-8 對(duì)字符串進(jìn)行編碼;

#? 它們使用 ISO 8601 格式來保存日期和日期時(shí)間數(shù)據(jù)嘴秸,以便這些數(shù)據(jù)不論在何種環(huán)境下都更容易解析毁欣。

#如果想要將 CSV 文件導(dǎo)為 Excel 文件,可以使用 write_excel_csv() 函數(shù)岳掐,

#該函數(shù)會(huì)在文件開頭寫入一個(gè)特殊字符(字節(jié)順序標(biāo)記)凭疮,告訴 Excel 這個(gè)文件使用的是 UTF-8 編碼。

#這幾個(gè)函數(shù)中最重要的參數(shù)是 x(要保存的數(shù)據(jù)框)和 path(保存文件的位置)串述。

#na 參數(shù)設(shè)定如何寫入缺失值执解,如果想要追加到現(xiàn)有的文件,需要設(shè)置 append 參數(shù)

write_csv(challenge, "challenge.csv")

#注意纲酗,當(dāng)保存為 CSV 文件時(shí)衰腌,類型信息就丟失了

#這使得 CSV 文件在暫存臨時(shí)結(jié)果時(shí)有些不可靠——每次加載時(shí)都要重建列類型。

#? write_rds() 和 read_rds() 函數(shù)是對(duì)基礎(chǔ)函數(shù) readRDS() 和 saveRDS() 的統(tǒng)一包裝觅赊。

#前者可以將數(shù)據(jù)保存為 R 自定義的二進(jìn)制格式右蕊,稱為 RDS 格式

write_rds(challenge, "challenge.rds")

read_rds("challenge.rds")

#feather 包實(shí)現(xiàn)了一種快速二進(jìn)制格式,可以在多個(gè)編程語言間共享:

library(feather)

write_feather(challenge, "challenge.feather")

read_feather("challenge.feather")

#feather 要比 RDS 速度更快吮螺,而且可以在 R 之外使用饶囚。

#RDS 支持列表列(我們將在第 19 章 中介紹),feather 目前還不行鸠补。

#其他類型的數(shù)據(jù)

#? haven 可以讀取 SPSS萝风、Stata 和 SAS 文件;

#? readxl 可以讀取 Excel 文件(.xls 和 .xlsx 均可);

#? 配合專用的數(shù)據(jù)庫后端程序(如 RMySQL、RSQLite紫岩、RPostgreSQL 等)规惰,DBI 可以對(duì)相

#應(yīng)數(shù)據(jù)庫進(jìn)行 SQL 查詢,并返回一個(gè)數(shù)據(jù)框泉蝌。

#對(duì)于層次數(shù)據(jù)歇万,可以使用 jsonlite(由 JeroenOoms 開發(fā))讀取 JSON 串揩晴,使用 xml2 讀取XML 文件。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末堕花,一起剝皮案震驚了整個(gè)濱河市文狱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缘挽,老刑警劉巖瞄崇,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異壕曼,居然都是意外死亡苏研,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門腮郊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摹蘑,“玉大人,你說我怎么就攤上這事轧飞⌒坡梗” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵过咬,是天一觀的道長(zhǎng)大渤。 經(jīng)常有香客問我,道長(zhǎng)掸绞,這世上最難降的妖魔是什么泵三? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮衔掸,結(jié)果婚禮上烫幕,老公的妹妹穿的比我還像新娘。我一直安慰自己敞映,他們只是感情好较曼,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著振愿,像睡著了一般诗芜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埃疫,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音孩哑,去河邊找鬼栓霜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛横蜒,可吹牛的內(nèi)容都是我干的胳蛮。 我是一名探鬼主播销凑,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼仅炊!你這毒婦竟也來了斗幼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤抚垄,失蹤者是張志新(化名)和其女友劉穎蜕窿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呆馁,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桐经,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浙滤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阴挣。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖纺腊,靈堂內(nèi)的尸體忽然破棺而出畔咧,到底是詐尸還是另有隱情,我是刑警寧澤揖膜,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布誓沸,位于F島的核電站,受9級(jí)特大地震影響次氨,放射性物質(zhì)發(fā)生泄漏蔽介。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一煮寡、第九天 我趴在偏房一處隱蔽的房頂上張望虹蓄。 院中可真熱鬧,春花似錦幸撕、人聲如沸薇组。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽律胀。三九已至,卻和暖如春貌矿,著一層夾襖步出監(jiān)牢的瞬間炭菌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工逛漫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黑低,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像克握,于是被迫代替她去往敵國(guó)和親蕾管。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容