数据框
数据框定义
统计分析中最常见的原始数据形式是类似于数据库表或Excel数据表的形式。
这样形式的数据在R中叫做数据框(data.frame)。
数据框类似于一个矩阵,有
但各列允许有不同类型:数值型向量、因子、字符型向量、日期时间向量。
同一列的数据类型相同。
在R中数据框是一个特殊的列表,
其每个列表元素都是一个长度相同的向量。
事实上,数据框还允许一个元素是一个矩阵,
但这样会使得某些读入数据框的函数发生错误。
函数data.frame()
可以生成数据框,如
d <- data.frame(
name=c("李明", "张聪", "王建"),
age=c(30, 35, 28),
height=c(180, 162, 175),
stringsAsFactors=FALSE)
print(d)
## name age height
## 1 李明 30 180
## 2 张聪 35 162
## 3 王建 28 175
data.frame()
函数会将字符型列转换成因子,
加选项stringsAsFactors=FALSE
可以避免这样的转换。
如果数据框的某一列为常数,
可以在data.frame()
调用中仅给该列赋一个值,
生成的结果会自动重复这个值使得该列与其他列等长。
nrow(d)
求d
的行数,ncol(d)
或length(d)
求d
的列数。
数据框每列叫做一个变量,
每列都有名字,称为列名或变量名,
可以用names()
函数和colnames()
函数访问。
如
给names(d)
或colnames(d)
赋值可以修改列名。
用as.data.frame(x)
可以把x
转换成数据框。
如果x
是一个向量,
转换结果是以x
为唯一一列的数据框。
如果x
是一个列表并且列表元素都是长度相同的向量,
转换结果中每个列表变成数据框的一列。
如果x
是一个矩阵,转换结果把矩阵的每列变成数据框的一列。
数据框是一个随着R语言前身S语言继承下来的概念,
现在已经有一些不足之处,
tibble包提供了tibble类,
这是数据框的一个改进版本。
见13.2。
数据框显示
在R markdown文件中,
可以将数据框保存的表格显示为富文本格式,
方法是使用knitr::kable()
函数。
详见A.4。
程序示例如:
name | age | height |
---|---|---|
李明 | 30 | 180 |
张聪 | 35 | 162 |
王建 | 28 | 175 |
数据框内容访问
数据框可以用矩阵格式访问,如
访问单个元素。
访问第二列,结果为向量。
也访问第二列,但是这种作法与tibble不兼容,
所以应避免使用。
按列名访问列可用如
其中d[,"age"]
的用法与tibble不兼容,应避免使用。
因为数据框的一行不一定是相同数据类型,
所以数据框的一行作为子集,
结果还是数据框,而不是向量。如
可以同时取行子集和列子集,如
d[1:2, "age"]
## [1] 30 35
d[1:2, c("age", "height")]
## age height
## 1 30 180
## 2 35 162
d[d[,"age"]>=30,]
## name age height
## 1 李明 30 180
## 2 张聪 35 162
与矩阵类似地是,
用如d[,"age"]
, d[,2]
这样的方法取出的数据框的单个列是向量而不再是数据框。
但是,如果取出两列或者两列以上,
结果则是数据框。
如果取列子集时不能预先知道取出的列个数,
则子集结果有可能是向量也有可能是数据框,
容易造成后续程序错误。
对一般的数据框,
可以在取子集的方括号内加上drop=FALSE
选项,
确保取列子集的结果总是数据框。
数据框的改进类型tibble在用d[,ind]
这种语法取出列子集时保持为tibble格式,
为了取出tibble中的一列作为向量,
应该使用d[[ind]]
这样的语法。
对数据框变量名按照字符串与集合进行操作可以实现复杂的列子集筛选,
但是建议使用23中所述的借助于tidyverse库的做法。
数据框的行名
数据框每一行可以有行名,
这在原始的S语言和传统的R语言中是重要的技术,
但是在改进类型tibble中则取消了行名,
需要用行名实现的功能一般改用left_join()
函数实现。
建议新的R程序不要再利用数据框的行名功能。
比如,每一行定义行名为身份证号,则可以唯一识别各行。
下面的例子以姓名作为行名:
用数据框的行名可以建立一个值到多个值的对应表。
比如,有如下的数据框:
dm <- data.frame(
"年级"=1:6,
"出游"=c(0, 2, 2, 2, 2, 1),
"疫苗"=c(TRUE, FALSE, FALSE, FALSE, TRUE, FALSE)
)
其中“出游”是每个年级安排的出游次数,
“疫苗”是该年级有全体无计划免疫注射。
把年级变成行名,可以建立年级到出游次数与疫苗注射的对应表:
这样,假设某个社区的小学中抽取的4个班的年级为c(2,1,1,3)
,
其对应的出游和疫苗注射信息可查询如下:
ind <- c(2,1,1,3)
dm[as.character(ind),]
## 出游 疫苗
## 2 2 FALSE
## 1 0 TRUE
## 1.1 0 TRUE
## 3 2 FALSE
结果中包含了不必要也不太合适的行名,可以去掉,以上程序改成:
## 出游 疫苗
## 1 2 FALSE
## 2 0 TRUE
## 3 0 TRUE
## 4 2 FALSE
如果要从多个值建立映射,
比如,从省名与县名映射到经度、纬度,
可以预先用paste()
函数把省名与县名合并在一起,
中间以适当字符(如`-“)分隔,
以这样的合并字符串为行名。
实际上,这个例子可以不用行名而是用match()
函数实现。match(x, table)
对x
的每个元素返回其在table
中出现的位置序号。
找不到的元素返回NA
。
如:
对于上面的学校年级信息查询的例子,
可以首先查找每个班对应的年级在数据框中的行序号,
然后再返回这些行组成的数据框:
dm <- data.frame(
"年级"=1:6,
"出游"=c(0, 2, 2, 2, 2, 1),
"疫苗"=c(T, F, F, F, T, F)
)
ind <- match(c(2,1,1,3), dm[["年级"]]); ind
## [1] 2 1 1 3
dm[ind,]
## 年级 出游 疫苗
## 2 2 2 FALSE
## 1 1 0 TRUE
## 1.1 1 0 TRUE
## 3 3 2 FALSE
对于代替数据框的tibble类型,
如果要实现行名的功能,
可以将行名作为单独的一列,
然后用dplyr包的inner_join()
、left_join()
、full_join()
等函数横向合并数据集。
参见23.23。
tibble
类型
生成方法
tibble类型是一种改进的数据框。
readr包的read_csv()
函数是read.csv()
函数的一个改进版本,
它将CSV文件读入为tibble类型,如文件class.csv
的读入:
## Rows: 19 Columns: 5
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): name, sex
## dbl (3): age, height, weight
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## # A tibble: 19 × 5
## name sex age height weight
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 Alice F 13 56.5 84
## 2 Becka F 13 65.3 98
## 3 Gail F 14 64.3 90
## 4 Karen F 12 56.3 77
## 5 Kathy F 12 59.8 84.5
## 6 Mary F 15 66.5 112
## 7 Sandy F 11 51.3 50.5
## 8 Sharon F 15 62.5 112.
## 9 Tammy F 14 62.8 102.
## 10 Alfred M 14 69 112.
## 11 Duke M 14 63.5 102.
## 12 Guido M 15 67 133
## 13 James M 12 57.3 83
## 14 Jeffrey M 13 62.5 84
## 15 John M 12 59 99.5
## 16 Philip M 16 72 150
## 17 Robert M 12 64.8 128
## 18 Thomas M 11 57.5 85
## 19 William M 15 66.5 112
tibble类型的类属依次为spec_tbl_df
, tbl_df
, tbl
, data.frame
:
用as_tibble()
可以将一个数据框转换为tibble,
dplyr包提供了filter()
、select()
、arrange()
、mutate()
等函数用来对tibble选取行子集、列子集,排序、修改或定义新变量,等等。
见23。
可以用tibble()
函数生成小的tibble,如
序号 | 收缩压 |
---|---|
1 | 145 |
5 | 110 |
6 | 未测 |
9 | 150 |
10 | 拒绝 |
15 | 115 |
在调用tibble()
函数时,
定义在后面的列可以调用前面的列的值。
用tribble
可以按类似于CSV格式输入一个tibble, 如
序号 | 收缩压 |
---|---|
1 | 145 |
5 | 110 |
6 | NA |
9 | 150 |
10 | NA |
15 | 115 |
注意tribble()
中数据每行末尾也需要有逗号,
最后一行末尾没有逗号。
这比较适用于在程序中输入小的数据集。
一列中混杂数值型和字符型会出错。
实际上,readr::read_csv()
也支持从一个多行字符串直接读入数据,
如:
## Rows: 6 Columns: 2
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (2): 序号, 收缩压
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
序号 | 收缩压 |
---|---|
1 | 145 |
5 | 110 |
6 | NA |
9 | 150 |
10 | NA |
15 | 115 |
tibble与数据框的一大区别是在显示时不自动显示所有内容,
这样可以避免显示很大的数据框将命令行的所有显示都充满。
没有显示的列的列名会罗列在显示下方,
显示时每列的类型同时显示,也会显示tibble的行列数。
可以在print()
用n=
和width=
选项指定要显示的行数和列数。
如果指定print(df, n=Inf, width=Inf)
,
则等同于对数据框的默认显示方式,
能够显示整个tibble,
但列数过多时会分页显示。
也可以用view(df)
在一个单独的窗口显示整个tibble。
tibble在生成或输入时不自动将字符型列转换为因子。
列子集问题
另外,用d[,ind]
这样的单重的方括号取列子集时,
即使仅取一列,
从tibble取出的一列结果仍是tibble而不是向量,
为了提取一列为向量应使用双方括号格式或$
格式。
因为这个原因有些原来的程序输入tibble会出错,
这时可以用as.data.frame()
转换成数据框。
如:
## # A tibble: 6 × 1
## 收缩压
## <chr>
## 1 145
## 2 110
## 3 未测
## 4 150
## 5 拒绝
## 6 115
如下的语法取出一列向量:
tibble在定义时不需要列名为合法变量名,
但是这样的变量名在作为变量名使用时需要用反单撇号包裹。
行名问题
tibble默认不使用行名(rownames)。
有行名的数据框用as_tibble()
转换为tibble时,
可以用rownames="变量名"
选项将行名转换成tibble的一列,
该列的变量名由选项值确定。
原来用行名完成的功能,
可以改用dplyr包的left_join()
等函数,
这些函数进行数据框的横向连接。
详见23。
实际上,旧式数据框支持行名,有如下的缺点:
- 行名本身往往也是有效的数据,如身份证号,
将有效数据以数据框中的列和行名两种不同形式保存,
增加了复杂度; - 为了使用某些变量辨识不同的行(观测),
行名也具有局限性:
行名必须是相互不同的,
必须是字符型,
而用来区分各个观测的变量有可能有多个,
也可能不是字符型。 - 行名要求互不相同是有局限性的,
如果用来辨识各行的变量有重复值,
就可以构成对各行的一种自然的分组。
bibble和数据框的转换
因为有一些老的R函数仅支持data.frame,
所以有时需要将tibble转换为数据框。
设dt
为tibble,
如果不需要添加行名,
则as.data.frame(dt)
就可以转换为data.frame。
如果需要添加行名,
设dt
中第一列要转换为行名,
转化的模板为
如果dt
中要转化为行名的列为id
列,
转化的模板为
反过来,
如果da是一个数据框,
要转化为tibble,
如果不需要保留行名,
则as_tibble(da)
就可以。
如果需要将行名转换为结果的一列,
模板为
则原来的行名变成了dt
的id
列。
必要的话,
tibble也支持行名,
这时,
只要用
就表示转换成tibble后仍保留原来的行名。
练习
假设class.csv
已经读入为R数据框d.class,
其中的sex列已经自动转换为因子。
- 显示d.class中年龄至少为15的行子集;
- 显示女生且年龄至少为15的学生姓名和年龄;
- 取出数据框中的age变量赋给变量x。
韭菜热线原创版权所有,发布者:风生水起,转载请注明出处:https://www.9crx.com/77957.html