Tidyverse

dplyr包: 数据转换

数据和包载入

1
2
3
library(nycflights13)
library(tidyverse)
nycflights13::flights

基础函数

以下5个函数参数相同:

  1. 第一个参数为数据框;
  2. 随后参数使用变量名称(不带引号)描述操作;
  3. 返回一个新的数据框;
filter(): 按值筛选

基于筛选条件筛选出观测子集:

1
2
3
4
subset <- filter(parentset, colname_1 == x_1, colname_2 == x_2)
#筛选出第一列中值为x_1,和第二列中值为x_2的行
(subset <- filter(parentset, colname_1 == x_1, colname_2 == x_2))
#在console中直接显示结果同时将值储存进subset
基于比较符
1
2
3
4
5
6
7
8
9
10
11
12
subset <- filter(parentset, colname_1 >= x_1, colname_2 <= x_2)
#比较运算符有: >,<,<=,>=,!=,==

#对于浮点数
sqrt(2)^2 == 2 #FALSE
1/49*49 == 1 #FALSE
#通常使用near()函数
near(sqrt(2)^2,2) #TRUE

#对于区间
subset <- filter(parentset, between(colname_1,3,9))
#选出位于区间(3,9)之间的colname值
基于逻辑符
1
2
3
4
subset <- filter(parentset, colname_1 >= x_1|colname_1 >= x_3)#或
subset <- filter(parentset, colname_1 >= x_1&colname_1 >= x_3)#与
subset <- filter(parentset, !(colname_1 >= x_1))#非
subset <- filter(parentset, colname_1 %in% c(x_1,x_2))
缺失值

缺失值 : 称为NA(Not available,不可用)

对于缺失值的操作也都是缺失值(大多数情况);

1
2
3
4
5
NA == NA
# 值为NA
x = NA;
is.na(x)
#TRUE

在筛选器中,为NA值得行和条件为FALSE的行会被过滤,如果需要保留;

1
subset <- filter(parentset,is.na(colname_1)|colname_1 >= x_3)

其他NA特殊操作的值:

1
2
3
NA^0 #=0
NA|TRUE #TRUE
NA*0 #=NA
arrange(): 对行排序
1
2
3
4
5
subset <- arrange(parentset, col_1, col_2, col_3)
#首先根据列1排序,再对列2排序,表示如果数据在“变量1”的值相同时按照“变量2”排序
subset <- arrange(parentset, desc(col_1), col_2, col_3)
#desc()函数使之降序排列,即descend
#缺失值无论降序还是升序,总是在最后
select(): 按名称选取
1
2
3
4
5
6
subset <- select(parentset, col_1, col_2, col_3)
#选取第1,2,3列
subset <- select(parentset, col_1:col_3)
#也是选取1:3列
subset <- select(parentset, -(col_1:col_3))
#选取不在1:3列间的列
辅助函数
1
2
3
4
5
6
7
8
9
10
starts_with(str): #以str开头的名称

end_with(str): #以str结尾的名称

contains(str):#包含str的名称

matches(pattern):#匹配正则pattern的名称

num_range("X",1:4):#匹配 {X1, X2, X3, X4 },神技
#会默认忽略大小写,如果要区分大小写,可以设置任意帮助函数的参数ignore.case = FALSE

select可以重命名变量,但是会丢失其他变量:

1
2
subset <- select(parentset, newname=oldname)

使用select的变体可以保留其他变量

1
rename(parentset, newname=oldname)

也可以使用everything()函数进行列排序:

1
2
subset <- select(parentset, col5,col3,everything())
#原顺序为1,2,3,4,5,现在为5,3,1,2,4

one_of(character_1,···,character_n):如果某个列的名字出现在序列里,则选出它

mutate(): 使用函数创建新变量
1
subset <- mutate(parentset, newcol1=col1/col2,newcol2=new1/col1)
  • 上述代码产生了两个新列, 总是加在数据框最后
  • 新列按顺序产生, 列一经产生即可使用(new2使用了new1)
  • 运算法则:
    • 加减乘除 “+”, “-”,”*”,”/”,”^”
    • 模运算:”%/%”整除,”%%”求余
    • 对数:log(),log2(),log10();
    • 偏移函数:lead(),lag(),前移或者后移一位
    • 累加,滚动聚合: 累加和,积,最小值,最大值:cumsum(), cumprod(), cummin(),cummax()
1
transmute(parentset, newcol1=col1/col2,newcol2=new1/col1)

只保留新的变量;

summarize(): 摘要统计量

summarize(),它可以将数据框折叠成一行:

1
2
3
4
5
summarize(flights, delay = mean(dep_delay, na.rm = TRUE))
#> # A tibble: 1 × 1
#> delay
#> <dbl>
#> 1 12.6

group_by() 可以将分析单位从整个数据集更改为单个分组.

1
2
3
4
5
6
7
8
9
10
11
12
13
by_day <- group_by(flights, year, month, day)
summarize(by_day, delay = mean(dep_delay, na.rm = TRUE))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day delay
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 11.55
#> 2 2013 1 2 13.86
#> 3 2013 1 3 10.99
#> 4 2013 1 4 8.95
#> 5 2013 1 5 5.73
#> 6 2013 1 6 7.15
管道操作符

即: “%>%”, 将返回值传递给管道符后的操作函数作为输入,通常可读作然后:

1
2
3
4
5
6
7
8
delays <- flights %>%
group_by(dest) %>%
summarize(
count = n(),
dist = mean(distance, na.rm = TRUE),
delay = mean(arr_delay, na.rm = TRUE)
) %>%
filter(count > 20, dest != "HNL")
缺失值忽略参数

na.rm=TRUE参数可以在计算前除去缺失值;

计数参数

即n(), 它的值是操作单位中值的个数;

常见摘要函数
位置: median()和mean()
1
2
3
4
5
6
7
8
not_cancelled %>%
group_by(year, month, day) %>%
summarize(
# 平均延误时间:
avg_delay1 = mean(arr_delay),
# 50%的x大于它,同时50%的x小于它。
avg_delay2 = median(arr_delay)
)
分散程度: sd(x)、IQR(x) 和mad(x)

分别是标准差, 四分位距, 绝对中位差;

1
2
3
not_cancelled %>%
group_by(dest) %>%
summarize(distance_sd = sd(distance))
秩: min(x)、quantile(x, 0.25) 和max(x)
1
2
3
4
5
6
not_cancelled %>%
group_by(year, month, day) %>%
summarize(
first = min(dep_time),
last = max(dep_time)
)
定位度量:first(x)、nth(x, 2) 和last(x)

和索引取值的区别在于,当定位不存在时取默认值位置;

1
2
3
4
5
not_cancelled %>%
group_by(year, month, day) %>%
summarize(
first_dep = first(dep_time),last_dep = last(dep_time)
)
计数:count()

唯一值计数:

1
n_distinct();

加权计数:

1
count(df , wt= weight)#weight可以是其他列或者别的权重
逻辑值计数: sum(x>a)和mean(x==0)

sum()使用逻辑表达式计数可以计算true值的个数;

而mean则可以直接获得比例,因为true值为1,FALSE为0;

按多个变量分组

当使用多个变量进行分组时,每次的摘要统计会==用掉一个分组变量==。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
daily <- group_by(flights, year, month, day)
(per_day <- summarize(daily, flights = n()))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day flights
#> <int> <int> <int> <int>
#> 1 2013 1 1 842
#> 2 2013 1 2 943
#> 3 2013 1 3 914
#> 4 2013 1 4 915
#> 5 2013 1 5 720
#> 6 2013 1 6 832
#> # ... with 359 more rows
(per_month <- summarize(per_day, flights = sum(flights)))
#> Source: local data frame [12 x 3]
#> Groups: year [?]
#>
#> year month flights
#> <int> <int> <int>
#> 1 2013 1 27004
#> 2 2013 2 24951
#> 3 2013 3 28834
#> 4 2013 4 28330
#> 5 2013 5 28796
(per_year <- summarize(per_month, flights = sum(flights)))
#> # A tibble: 1 × 2
#> year flights
#> <int> <int>
#> 1 2013 336776
  1. 但是取加权平均或者方差或者中位数时,很容易出错,因为对整体取中位数和分组取中位数在取中位数完全不同;
  2. 可以用ungroup()取消分组

tibble数据框

创建tibble数据框

1
2
3
as_tibble(df)#从普通数据框转换

tibble(x=vector,y=vector,z=vector)#直接创建
  • tibble相比较data.frame: 不能改变输入的类型(例如,不能将字符串转换为因子)、变量的名称,也不能创建行名称。
  • 可以在tibble 中使用在R 中无效的变量名称(即不符合语法的名称)作为列名,需要使用反引号` 将它们括起来
1
2
3
4
5
tb <- tibble(
`:)` = "smile",
` ` = "space",
`2000` = "number"
)
  • transposed tibble: 列标题由公式(以~ 开头)
    定义,数据条目以逗号分隔,对少量数据进行布局
1
2
3
4
5
6
7
8
9
10
tribble(
~x, ~y, ~z,
#--|--|----
"a", 2, 3.6,
"b", 1, 8.5)
#> # A tibble: 2 × 3
#> x y z
#> <chr> <dbl> <dbl>
#> 1 a 2 3.6
#> 2 b 1 8.5
打印tibble()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
tibble(
a = lubridate::now() + runif(1e3) * 86400,
b = lubridate::today() + runif(1e3) * 30,
c = 1:1e3,
d = runif(1e3),
e = sample(letters, 1e3, replace = TRUE)
)
#> # A tibble: 1,000 × 5
#> a b c d e
#> <dttm> <date> <int> <dbl> <chr>
#> 1 2016-10-10 17:14:14 2016-10-17 1 0.368 h
#> 2 2016-10-11 11:19:24 2016-10-22 2 0.612 n
#> 3 2016-10-11 05:43:03 2016-11-01 3 0.415 l
#> 4 2016-10-10 19:04:20 2016-10-31 4 0.212 x
#> 5 2016-10-10 15:28:37 2016-10-28 5 0.733 a
#> 6 2016-10-11 02:29:34 2016-10-24 6 0.460 v
#> # ... with 994 more rows
nycflights13::flights %>%
print(n = 10, width = Inf)#width显示宽度,n为行数
#可通过设置选项(option)控制默认打印方式
options(tibble.print_max = n, tibble.print_min = m)
取子集
1
2
3
4
5
6
7
8
9
10
11
12
13
df <- tibble(
x = runif(5),
y = rnorm(5)
)
df$x #$只能通过名字提取
df[["x"]]
df[[1]]# 双中括号既可以按名称也可以按位置

#与管道符结合
df %>% .$x #.为占位符,功能如其名
#> [1] 0.434 0.395 0.548 0.762 0.254
df %>% .[["x"]]
#> [1] 0.434 0.395 0.548 0.762 0.254

readr

读取文件

  • csv文件: read_csv()读取逗号分隔文件、read_csv2() 读取分号分隔文件(这在用, 表示小数位的国家非常普遍)、read_tsv() 读取制表符分隔文件、read_delim() 可以读取使用任意分隔符的文件。
  • read_fwf() 读取固定宽度的文件。既可以使用fwf_widths() 函数按照宽度来设定域,也可以使用fwf_positions() 函数按照位置来设定域。read_table() 读取固定宽度文件的一种常用变体,其中使用空白字符来分隔各列。
参数

direction: 绝对or相对路径

1
2
3
4
heights <- read_csv("data/heights.csv")
read_csv("a,b,c
1,2,3
4,5,6")#也可以读取行内CSV文件,换行不能省!

skip = n:跳过前N行:

comment = char: 丢弃所有以char开头的行,即将其注释掉

col_names = FALSE: 不使用数据的第一行作为列名称(默认为TRUE. 标注为X1 X2 X3 ….;或者使用向量为其命名;

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

解析向量

  • parse_*() 函数族: 接受一个字符向量,并返回一个特定向量,如逻辑、整数或日期向量:
1
parse_integer(c("1", "231", ".", "456"), na = ".")#"na="哪些字符串应该当作缺失值来处理
  • 解析失败的值在输出中是以缺失值的形式存在的

  • problems() 函数来获取完整的失败信息集合(tibble)

  • parse_double()解析浮点数,,parse_number() 则是灵活的数值型解析函数。

1
2
3
4
5
parse_double("1,23", locale = locale(decimal_mark = ","))#“地区"根据地区设置解析选项
parse_number(
"123.456.789",
locale = locale(grouping_mark = ".")
)
1
2
3
4
5
6
7
#parse_number()忽略数值前后的非数值型字符
parse_number("$100")
#> [1] 100
parse_number("20%")
#> [1] 20
parse_number("It cost $123.45")
#> [1] 123
  • parse_character():

    • charToRaw()获得字符串ASCII编码

    • 设定编码方式

      1
      2
      3
      4
      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] "こんにちは"
    • 未知编码方式:

      1
      2
      3
      4
      5
      6
      7
      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
  • parse_factor(): R 使用因子表示取值范围是已知集合的分类变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
fruit <- c("apple", "banana")
parse_factor(c("apple", "banana", "bananana"), levels = fruit)
#> Warning: 1 parsing failure.
#> row col expected actual
#> 3 -- value in level set bananana
#> [1] apple banana <NA>
#> attr(,"problems")
#> # A tibble: 1 × 4
#> row col expected actual
#> <int> <int> <chr> <chr>
#> 1 3 NA value in level set bananana
#> Levels: apple banana
#存在向量中没有的值,生成一条警告
  • 时间解析:

    • parse_datetime():

      1
      2
      parse_datetime("2010-10-01T2010")
      #> [1] "2010-10-01 20:10:00 UTC"
    • parse_date():

      1
      2
      parse_date("2010-10-01")
      #> [1] "2010-10-01"
    • parse_time():

      1
      2
      3
      library(hms)
      parse_time("20:10:01")
      #> 20:10:01
    • 自定义格式

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      parse_date("01/02/15", "%m/%d/%y")

      #%Y(4 位数)。
      #%y(2 位数;00-69 → 2000-2069、70-99 → 1970-1999)。

      #%m(2 位数)。
      #%b(简写名称,如Jan)。
      #%B(完整名称,如January)。

      #%d(1 位或2 位数)。
      #%e(2 位数)
      时间
      #%H(0-23 小时)。
      #%I(0-12 小时,必须和%p 一起使用)。
      #%p(表示a.m./p.m.)。
      #%M(分钟)。
      #%S(整数秒)。
      #%OS(实数秒)。
      #%Z(时区,America/Chicage 这样的名称)。注意,要当心缩写。如果你是美国人,注意
      #EST 是加拿大没有夏时制的一个时区。它表#示东部标准时间!我们还会在12.5 节中继
      #续讨论这个话题。
      #%z(与国际标准时间的时差,如+0800)。
      #非数值字符
      #%.(跳过一个非数值字符)。
      #%*(跳过所有非数值字符)。

解析文件

ggplot2

基础图画绘制

数据(Data)和映射(Mapping)

数据要求

用于绘制图形的data frame或者tibble.

映射

aes()函数是ggplot2中的映射函数, 所谓的映射即为数据集中的数据关联到相应的图形属性过程中一种对应关系, 图形的颜色,形状,分组等都可以通过通过数据集中的变量映射。


将钻石数据集中克拉和价格映射为X,Y轴变量:

1
p <- ggplot(data = diamond, mapping = aes(x = carat, y = price))

#将钻石的颜色(color)映射颜色属性:

1
2
p <- ggplot(data=diamond, mapping=aes(x=carat, y=price, shape=cut, colour=color))
p+geom_point() #绘制点图

#将钻石的切工(cut)映射到形状属性:

1
2
p <- ggplot(data=diamond, mapping=aes(x=carat, y=price, shape=cut))
p+geom_point() #绘制点图

#将钻石的切工(cut)映射到分组属性:

1
2
3
4
#默认分组设置, 即group=1p + geom_boxplot()
#分组(group)也是ggplot2种映射关系的一种, 如果需要把观测点按额外的离散变量进行分组处理, 必须修改默认的分组设置。
p1 <- ggplot(data=diamond, mapping=aes(x=carat, y=price, group=factor(cut)))
p1 + geom_boxplot()

几何对象(Geometric)

直方图

单变量连续变量:可绘制直方图展示,提供一个连续变量,画出数据的分布。

1
2
ggplot(diamond)+geom_histogram(aes(x=price, fill=cut))
#以价格(price)变量为例,且按照不同的切工填充颜色(即一个直方内有不同颜色的切工块)
1
2
ggplot(diamond)+geom_histogram(aes(x=price, fill=cut), position="dodge")
#dodge选项使得原本纵向分布的"切工"块变为并列显示
1
2
ggplot(diamond)+geom_histogram(aes(x=price, fill=cut), position="fill")
#设置使用position="fill",按相对比例画直方图,可以显示不同价格时,各切工所占比例
柱状图

单变量分类变量:可使用柱状图展示,提供一个x分类变量,画出数据的分布。

1
2
3
ggplot(diamond)+geom_bar(aes(x=clarity, fill=cut))
#以透明度(clarity)变量为分类,且按照不同的切工填充颜色
#ggplot自动计算分类数
箱式图

箱线图: 通过绘制观测数据的五数总括,即最小值、下四分位数、中位数、上四分位数以及最大值,描述了变量值的分布情况。

1
2
ggplot(diamond)+geom_boxplot(aes(x=cut, y=price,fill=color))
#按切工(cut)分类,对价格(price)变量画箱式图,再按照color变量分别填充颜色。

标尺(Scale)

在对图形属性进行映射之后,使用标尺可以控制这些属性的显示方式,比如坐标刻度,颜色属性等。

scale函数命名通式: 一般使用三个单词用”_”连接:

  1. 第一个都是scale
  2. 第二个是color fill x y linetype shape size等可更改的参数
  3. 第三个是具体的类型.
颜色标尺
第二个参数

对于颜色scale函数,第二个有两个参数, 一个是fill,主要是指填充颜色;另一个是color,指点或者线的颜色;

第三个参数

根据数据为离散型还是连续性决定;

1)离散型:在颜色变量是离散变量的时候使用,比如分类时每一类对应一种颜色

  • manual 直接指定分组使用的颜色
  • hue 通过改变色相(hue)饱和度(chroma)亮度(luminosity)来调整颜色
  • brewer 使用ColorBrewer的颜色
  • grey 使用不同程度的灰色

manual 参数:

1
2
3
p+scale_fill_manual(values=c("red", "blue","green","yellow","orange"))
p+scale_fill_manual(values=c("Fair"="red","Good" = "blue", "Very Good" = "green", Premium = "orange", Ideal = "yellow"))
p + scale_fill_manual("class", values=c("red", "blue", "green","yellow","orange"),breaks = c("Fair", "Good", "Very Good","Premium","Ideal"),labels = c("一般", "好", "很好", "高级", "理想"))

brewer 使用ColorBrewer的颜色:

1
2
3
4
5
6
7
library(RColorBrewer)
#主要是palette参数调用色板
p + scale_fill_brewer()
# 默认使用Blues调色板中的颜色
p + scale_fill_brewer(palette = "Greens")
#使用Greens调色板中的颜色
p + scale_fill_brewer(palette = "Greens",direction = -1)

direction参数决定颜色顺序, 为-1则反着来;

grey 使用不同程度的灰色:

通过start end 两个参数指定,0为黑,1为白,都在0-1范围内

1
2
3
4
p + scale_fill_grey()  
#设定灰度范围
p + scale_fill_grey(start=1, end=0)
p + scale_fill_grey(start=1, end=0.5)

2)连续型:颜色变量是连续变量的时候使用,比如0-100的数,数值越大颜色越深这样

  • gradient 创建渐变色
  • distiller 使用ColorBrewer的颜色
  • identity 使用color变量对应的颜色,对离散型和连续型都有效
1
2
df <- data.frame(x = runif(100),y = runif(100),z1 = rnorm(100))
p <- ggplot(df, aes(x, y)) + geom_point(aes(colour = z1))

gradient 创建渐变色#参数设定节点颜色:

1
2
3
4
5
6
7
8
9
#设置两端颜色p + scale_color_gradient(low = "white", high = "black")
#设置中间过渡色
p + scale_color_gradient2(low = "red", mid = "white", high = "blue")
#使用R预设调色板
p + scale_color_gradientn(colours =rainbow(10))
#legeng展示指定标签
p + scale_color_gradient(low = "white", high = "black", breaks=c(1,2,0.5), labels=c("a","b","c"))
#legend名称
p + scale_color_gradient("black", low = "white", high = "black", limits=c(0.5,2))

distiller 使用ColorBrewer的颜色:

1
2
p + scale_color_distiller(palette = "Spectral")
p + scale_color_distiller(palette = "Greens")
坐标轴尺度修改

参数与上类似,第一个参数为scale, 然后是x,y表明对哪个轴操作,最后是详细操作;

  • 更改坐标轴名称
  • 更改x轴上标数的位置和内容
  • 显示对一个轴做统计变换
  • 只展示一个区域内的点
  • 更改刻度标签的位置
1
2
3
4
5
6
7
8
# 横坐标是离散变量,纵坐标是连续变量
p <- ggplot(mtcars, aes(factor(cyl), mpg)) + geom_point()
# 更改坐标轴名称
p + scale_x_discrete("cyl")
# 更改横轴标度
p + scale_x_discrete(labels = c("4"="a","6"="b","8"="c"))
# 指定横轴顺序以及展示部分
p + scale_x_discrete(limits=c("6","4"))
1
2
3
4
5
6
7
8
9
10
11
12
# 连续变量可以更改标度(图与上相似,略)
p + scale_y_continuous("ylab_mpg")
p + scale_y_continuous(breaks = c(10,20,30))
p + scale_y_continuous(breaks = c(10,20,30), labels=scales::dollar)
p + scale_y_continuous(limits = c(10,30))
# 连续变量可以更改标度,还可以进行统计变换
p + scale_y_reverse() # 纵坐标翻转,小数在上面,大数在下面
p + scale_y_log10()
p + scale_y_continuous(trans = "log10")
p + scale_y_sqrt()
# 更改刻度标签的位置
p + scale_x_discrete(position = "top") + scale_y_continuous(position = "right")