R 包 `ezdf`的講解

作者簡介Introduction

數據匠(baidao.net):baidao.net/

往期回顧

談談R中的亂碼(一)mp.weixin.qq.com圖標談談R中的亂碼(二)mp.weixin.qq.com圖標談談R中的亂碼(三)mp.weixin.qq.com圖標

目的

  • 在導入 SPSS Stata 等格式時,提供統一的處理標籤的介面;
  • 在輸出表格時提供對標籤的自動化處理;

什麼是標籤

SPSS 和 Stata 的用戶最熟悉標籤:

  • 變數標籤

gender `性別`

age `年齡`

  • 數值標籤

gender:

1 = 男性

2 = 女性

R 中如何處理標籤

首先,data.frame 沒有變數標籤的概念(attr 另外再說),變數名行使標籤的功能:

table(dt$`性別`)

# 如果標籤有空格

table(dt$`a variable`)

其次,可用 factor 提供數值標籤功能(factor 其實就等價於字元型):

levels(df$`性別`) <- c(男, 女)

R 包對標籤的處理

通過對象屬性設置來保存標籤:

  • foreign

attr(df, variable.labels) # 變數標籤

attr(var, value.labels) # 數值標籤

  • haven

和 foreign 道理一樣,只不過命名方式不同。此外,haven 把變數標籤和數值標籤都作為變數的屬性,而在 foreign 中,變數標籤是 data.frame 的屬性,數值標籤才是變數的屬性。

attr(var, label)

attr(var, labels)

顯示在 RStudio 中是這樣的:

ezdf 提供統一的數據導入介面

  • 對數據導入提供統一介面,封裝 foreign、haven 等包的導入函數;
  • 修正一些 bug,例如:

`haven`: 「Error: `x` and `labels` must be same type」

導入 Stata 數據

導入 Stata 數據使用 readStata() 函數:

library(ezdf)

dat <- readStata(CGSS2013(居民問卷)發布版_2014.dta, encoding = GB2312) # View(dat)

# 參數 `encoding` 設置 Stata 標籤的編碼,該參數默認值為 UTF-8。

# 有的 Stata 數據對變數名以及字元變數(string)的值都採用不同編碼,對於這種情況,

# 需分別設置 `varNameEncoding` 和 `charEncoding`。 dat <- readStata(CGSS2013(居民問卷)發布版_2014.dta, encoding = GB2312, varNameEncoding = UTF-8, charEncodin = UTF-8)

導入 SPSS 數據

導入 SPSS 數據使用 readSPSS() 函數

# 參數 `lib` 設置導入所使用的 R 包,目前支持 `foreign` 和 `haven`。

readSPSS(file, lib = "foreign", ...)

將 data.frame 轉換為 ezdf

用 as.ez(dt, meta) 創建一個新的 ez.data.frame 對象

data(iris)

library(ezdf)

d1 = as.ez(iris) class(d1)

## [1] "ez.data.frame" "data.table" "data.frame"

ezdf 對標籤的設置

變數標籤

  • 變數標籤存儲在 meta 屬性當中;
  • meta 可為 data.frame 或 matrix 類型對象:至少包括兩列:第一列為變數名,第二列為變數標籤。

兩個輔助函數:

- `setmeta()`

- `getmeta()`

d1$test = sample(5, size = nrow(iris), replace = T)

# 對新變數 test 設置變數標籤

setmeta(d1, data.frame(var= test, lbl = 這是新變數標籤))

# 顯示數據 d1 的全部變數標籤 attr(d1, meta)

## var lbl

## 1: test 這是新變數標籤

# 或者

getmeta(d1)

## var lbl

## 1: test 這是新變數標籤

varLabels(d1, c(Species, test)) ## [1] "" "這是新變數標籤"

# 用 default = "var" 只輸出帶有標籤的變數

varLabels(d1, c(Species, test), default = "var")

## [1] "Species" "這是新變數標籤"

# 返回所有已定義的變數標籤

varLabels(d1)

## var lbl

## 1: test 這是新變數標籤

單獨設置部分變數標籤

# 設置變數標籤

varLabels(d1, "test") <- "新標籤"

varLabels(d1, "test")

## [1] "新標籤"

數值標籤

數值標籤的存儲採用命名整數向量作為變數的 labels 屬性

# 定義一個數值標籤

c(C1 = 1, C2 = 2, C3 = 3, MI = 9)

  • valueLabels()

vl1 = valueLabels(d1, test)

vl1

## list()

## attr(,"class")

## [1] "value.labels"

## attr(,"ez")

## [1] "d1"

## attr(,"col")

## [1] "test"

# 數值標籤可以「加減」。

# 注意: MI=9 設了一個不存在的值標籤

vl2 = vl1 + c("Class1"=1, "Class2"=2, "Class3"=3, Class4=4, Class5 = 5, MI = 9, MM = 8) valueLabels(d1, test) = vl2

製表函數

tbl()

tbl(d1, ~test)

## test 新標籤 N

## 1: 1++Class1 25

## 2: 2++Class2 37

## 3: 3++Class3 23

## 4: 4++Class4 25

## 5: 5++Class5 40

# 分組求均值,添加樣本數

tbl(d1, Sepal.Length ~ Species + test, mean, N = T)

## Species test 新標籤 Sepal.Length N

## 1: setosa 1++Class1 5.141667 12

## 2: setosa 2++Class2 4.923077 13

## 3: setosa 3++Class3 5.200000 5

## 4: setosa 4++Class4 5.044444 9

## 5: setosa 5++Class5 4.836364 11

## 6: versicolor 1++Class1 5.900000 4

## 7: versicolor 2++Class2 5.941667 12

## 8: versicolor 3++Class3 5.908333 12

## 9: versicolor 4++Class4 6.142857 7

## 10: versicolor 5++Class5 5.866667 15

## 11: virginica 1++Class1 6.533333 9

## 12: virginica 2++Class2 6.583333 12

## 13: virginica 3++Class3 6.883333 6

## 14: virginica 4++Class4 6.344444 9

## 15: virginica 5++Class5 6.657143 14

# tbl() 默認按照公式右端 x 的值排序,如果取消排序

tbl(d1, Sepal.Length ~ Species + test, mean, N = T, sort = F)

## Species test 新標籤 Sepal.Length N

## 1: setosa 4++Class4 5.044444 9

## 2: setosa 5++Class5 4.836364 11

## 3: setosa 1++Class1 5.141667 12

## 4: setosa 2++Class2 4.923077 13

## 5: setosa 3++Class3 5.200000 5

## 6: versicolor 4++Class4 6.142857 7

## 7: versicolor 2++Class2 5.941667 12

## 8: versicolor 5++Class5 5.866667 15

## 9: versicolor 3++Class3 5.908333 12

## 10: versicolor 1++Class1 5.900000 4

## 11: virginica 4++Class4 6.344444 9

## 12: virginica 5++Class5 6.657143 14

## 13: virginica 2++Class2 6.583333 12

## 14: virginica 1++Class1 6.533333 9

## 15: virginica 3++Class3 6.883333 6

ctbl()

ctbl() 是對 table() 的封裝,採用 ctbl(ez, expr) 的調用方式。

ctbl(d1, Sepal.Length ~ Species + test)

# 等價於

table(d1$Sepal.Length, d1$Species, d1$test)

ftable()

ftable.ez.data.frame() 方法是對 ftable() 的封裝

ftable(ez, formula, style = 1, prop_margin = 1, ...)

  • prop_margin: 行百分比 / 列百分比;
  • style = 1:輸出頻次;
  • style = 2:輸出百分比;
  • style = 3:輸出百分比和行加總頻次。

ftable(d1, Species~test)

##

## setosa versicolor virginica

## 1++Class1 12 4 9

## 2++Class2 13 12 12

## 3++Class3 5 12 6

## 4++Class4 9 7 9

## 5++Class5 11 15 14

ftable(d1, Species~test, style = 2)

##

## setosa versicolor virginica

## 1++Class1 0.4800000 0.1600000 0.3600000

## 2++Class2 0.3513514 0.3243243 0.3243243

## 3++Class3 0.2173913 0.5217391 0.2608696

## 4++Class4 0.3600000 0.2800000 0.3600000

## 5++Class5 0.2750000 0.3750000 0.3500000

(t1 = ftable(d1, Species~test, style = 3))

## setosa versicolor virginica N

## 1++Class1 0.4800000 0.1600000 0.3600000 25

## 2++Class2 0.3513514 0.3243243 0.3243243 37

## 3++Class3 0.2173913 0.5217391 0.2608696 23

## 4++Class4 0.3600000 0.2800000 0.3600000 25

## 5++Class5 0.2750000 0.3750000 0.3500000 40

與 markdown 流程整合

  • pander 是用於 markdown 格式輸出的 R 包,提供了非常豐富的表格輸出功能
  • 在載入 ezdf 包之後,會自動與 pander 包結合,實現自動標籤輸出

# pander 輸出

library(pander) pander(t1, ez = d1)

這是輸出的 markdown 結果:

----------------------------------------------------

&nbsp; setosa versicolor virginica N

--------------- -------- ------------ ----------- ---

**1++Class1** 0.48 0.16 0.36 25

**2++Class2** 0.3514 0.3243 0.3243 37

**3++Class3** 0.2174 0.5217 0.2609 23

**4++Class4** 0.36 0.28 0.36 25

**5++Class5** 0.275 0.375 0.35 40

-----------------------------------------------------

最終輸出效果:

pander 與回歸結果輸出:

# 加上數值標籤

options(ezdfKeepVal = T)

pander(tbl(dat, a66 ~ s5a, mean))

---------------------------------------------------------

s5a 受訪者居住的地區類型是 a66 您家是否擁有家用小汽車

---------------------------- ----------------------------

1++市/縣城的中心地區 1.761

2++市/縣城的邊緣地區 1.775

3++市/縣城的城鄉結合部 1.809

4++市/縣城區以外的鎮 1.859

5++農村 1.919

---------------------------------------------------------

數值與標籤之間分隔符

options(ezdfValueLabelSep = =)

pander(tbl(dat, a66 ~ s5a, mean))

---------------------------------------------------------

s5a 受訪者居住的地區類型是 a66 您家是否擁有家用小汽車

---------------------------- ----------------------------

1=市/縣城的中心地區 1.761

2=市/縣城的邊緣地區 1.775

3=市/縣城的城鄉結合部 1.809

4=市/縣城區以外的鎮 1.859

5=農村 1.919

---------------------------------------------------------

回歸模型的輸出:

m1 = lm(a6 ~ a2 + a10, dat)

pander(m1)

這是通過 markdown 輸出轉成 pdf 後的效果,沒有任何手工干預(pandoc 在輸出小數點時,還有一點瑕疵,比如小數點位數不統一,不過本人 github 上的版本已經修正了這個問題)。

表格輸出選項

目前提供三個選項:

  • options(ezdfKeepVal = T)
  • options(ezdfValueLabelSep = =)
  • options(ezdfKeepVarName = T)

options(ezdfKeepVal = T)

options(ezdfValueLabelSep = =)

options(ezdfKeepVarName = F)

tbl(d1, ~test)

## 新標籤 N

## 1: 1=Class1 25

## 2: 2=Class2 37

## 3: 3=Class3 23

## 4: 4=Class4 25

## 5: 5=Class5 40

pander(tbl(d1, ~test))

options(ezdfKeepVarName = T)

options(ezdfValueLabelSep = ++)

pander(tbl(d1, ~test))

下載與安裝

github:

huashan/ezdfgithub.com圖標

往期精彩內容整理合集

2017年R語言發展報告(國內)mp.weixin.qq.com圖標R語言中文社區歷史文章整理(作者篇)mp.weixin.qq.com圖標R語言中文社區歷史文章整理(類型篇)mp.weixin.qq.com圖標
推薦閱讀:

TAG:R編程語言 | 數據分析 | 數據挖掘 |