「R语言刷题笔记」数据类型篇 - 从tidyr和dplyr入手

R语言到底可以用来做什么?

在生物信息学领域,大数据、机器学习等方向,和Python一比,我感觉已经相形见绌,

所以为什么还要学习R语言?

1)ggplot2的绘图体系非常完美

2)R base能够完成我日常小数据的分析

有很多人说,tidyverse给了R二次生命,但是在我看来它的编程思维,稍显奇怪,不太能够适应,

但是我属于一个钻牛角尖的人,既然学了,而且R我也没有完全丢掉,也是有一定必要学习一些重获新生的R语言。

因此这篇文章就是针对我在最近的R语言刷题中的总结。

数据读入 / 写出

从R base的角度看问题

read.table()
read.csv()
write.table()
write.csv()

readr的角度看问题

read_csv()
read_delim()
read_table()
write_delim(df, 'filename.csv')
write_csv(df, 'filename.csv')
write_excel_csv(df, 'filename.csv')
write_tsv(df, 'filename.csv')

data.frame

从R base的角度看问题

如何随心所欲的操作data.frame

使用data.frame()创建数据库,

1)给定colname,再给定该变量对应的element(一般是vector格式),即

<center>colname=c(elements)</center>

2)依此类推,增添每一列

# 1. 数据框的创建
df <- data.frame(
  "grammer" = c("Python","C","Java","GO",NA,"SQL","PHP","Python"),
  "score" = c(1,2,NA,4,5,6,7,10)
)

tidyr的角度看问题

library(tidyr)
df <- tibble(
  "grammer" = c("Python","C","Java","GO",NA,"SQL","PHP","Python"),
  "score" = c(1,2,NA,4,5,6,7,10)
)
# # A tibble: 8 x 2
#   grammer score
#   <chr>   <dbl>
# 1 Python      1
# 2 C           2
# 3 Java       NA
# 4 GO          4
# 5 NA          5
# 6 SQL         6
# 7 PHP         7
# 8 Python     10

dplyr的衔接

dplyr提供了一系列用C++重新编写过的函数,能够加快我们处理数据的速度。

主要包含的函数如下,

select()
filter()
mutate()
group_by()
arrange()

1)数据框列名的重新命名:names(), colnames(), rename()

R base对列名进行修改的话,使用如下格式,

# R base
names(df)[2] <- c('popularity')

# dplyr
df <- df %>% rename(popularity = score)

2)数据过滤:which(), filter()

# R base
df[which(df$popularity > 3), ]

# dplyr
df %>%
  filter(popularity > 3)

# 按照范围也是一样的,
df %>%
  filter(popularity > 3 & popularity <7)

3)选择某一列数据:$, select()

# R base
df$popularity

# dplyr
df <- df %>%
    select(popularity, everything())

Note:tidyverse::everything()的作用,为选择数据框中的所有变量。

select()函数一起使用,可以改变数据框中变量的排列顺序(e.g. 将变量A从变量B后移动到变量B前),以iris数据集为例,

select(iris, everything())
#  A tibble: 150 x 5
#    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#           <dbl>       <dbl>        <dbl>       <dbl> <fct>  
#  1          5.1         3.5          1.4         0.2 setosa
select(iris, Species, everything())
# # A tibble: 150 x 5
#    Species Sepal.Length Sepal.Width Petal.Length Petal.Width
#    <fct>          <dbl>       <dbl>        <dbl>       <dbl>
#  1 setosa           5.1         3.5          1.4         0.2

可以看到Species被提前了。

4)将一行/多行数据添加到数据框中:rbind()

row <- data.frame(
  "grammer" = c("Perl"),
  "popularity" = c(6.6)
)
df <- rbind(df, row)

5)分组:aggregate(), group_by

  • R base:aggregate()
  • dplyr:group_by + summarise
# R base
# 使用aggregate对df进行分组计算
library(flipAPI)
data = DownloadXLSX("https://wiki.q-researchsoftware.com/images/1/1b/Aggregation_data.xlsx", want.row.names = FALSE, want.data.frame = TRUE)
data.agg = aggregate(df,
                by = list(data$Role),
                FUN = mean)

# dplyr
# 使用group_by()分组,并进行相关计算
library(readr)
df <- read_csv('pandas120.csv')
df %>%
  group_by(education) %>%    # 设置用于分组的变量,此处为education
  summarise(mean = mean(salary))

6)构建新的一列变量:mutate()

# R base
# 使用cbind()函数

# dplyr
df <- df %>%
  mutate(test = paste0(df$education, df$createTime))

Note:paste0,先将变量转换为字符类型

7)将某一列的设置为索引:rownames(), column_to_rownames()

# R base
rownames(df) <- df$createTime

# dplyr
# 使用column_to_rownames,该函数将某一列设置为行名后得到
df %>%
  tibble::column_to_rownames('createTime')

8)数据排序

# R base
# sort(): 返回的是排序后的结果
# order()
df <- df[order(df$popularity), ]

# dplyr
# 使用arrange()
df <- df %>%
  arrange(popularity)
df <- df %>%
  arrange(desc(popularity))

9)数据的总结:summary(), summarize()

data.frame有关的实例

1)填补NA

1)使用R包Hmisc中的impute()函数
2)<u>使用impute函数的一般模式</u>,一为输入的向量,二为如何填充NA值所定义的<font color='yellow'>FUN</font>

Note:下列代码中的unlist,只是为了安全作用

library(Hmisc)
index <- which(is.na(df$popularity))
df$popularity <- impute(df$popularity,
                       (unlist(df[index-1, 2] +
                               df[index+1, 2]))/2)

2)将宽数据转换为长数据

使用tidyr中的pivot_longer()函数,

一般的使用模式如下,

pivot_longer(data, 
             cols, names_to = "name",  # cols,定义一个vector用于选择df中的列并进行合并
             values_to = "value",      # 每一行对应的元素
             values_drop_na = FALSE)

举个例子,

library(tidyr)
df %>%
  select(日期,`开盘价(元)`,`收盘价(元)`) %>%
  pivot_longer(c(`开盘价(元)`,`收盘价(元)`),
               names_to='type',values_to='price') %>%
  ggplot(aes(日期,price,color=type)) +
  geom_line(size=1.2) +
  scale_color_manual(values=c('steelblue','orange')) +
  theme_bw() +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    legend.title = element_blank(),
    legend.position = c(0.86, 0.9)
 )

3)读入数据的测试

假设现在有一个非常大的数据集,但是可以用read.csv等函数进行读入,然后后续用到的数据实际上只占了df的2列,

1)如何找到这两列?

2)如何在后续的分析中只读取到这两列?

res <- read.csv('数据1.csv',encoding = 'GBK',nrows = 3)  # 测试读入3行数据

# 获取每一列的数据类型(e.g. integer、character)
classes <- sapply(res, class)
classes[-match(c('positionName','salary'), names(classes))] <- 
    rep('NULL', length(classes) - 2)  # 保留只想要选择的列

df <- read.csv('数据1.csv', encoding = 'GBK', nrows = 10,
               colClasses = classes) # 使用"colClasses="指定列

代码的解读,

1)测试读入数据,即读取3行
2)使用sapply获取每一列的数据类型
3)去除不想要的列的数值类型,即 ->None
4)重新使用read.csv(, colClasses=),对目的数据进行读取

4)使用sapply()创建一个数据框

df1 <- sapply(20, function(n){
  replicate(n, sample(1:100, 1))
}) %>%
  as.data.frame(.) %>%
  dplyr::rename(`0` = V1)

R tips

str():查看对象每一个子对象的类型

R中有非常多的对象,比如

  • data.frame中的每一个变量都是一个子对象,
  • 列表中的每一个$,均为一个子对象
str(df)
# 'data.frame':   8 obs. of  2 variables:
#  $ grammer: Factor w/ 6 levels "C","GO","Java",..: 5 1 3 2 NA 6 4 5
#  $ score  : num  1 2 NA 4 5 6 7 10

.:既是占位符,也是通配符

.在一些情况下,可以充当占位符,比如下列代码的含义为过滤掉salary小于10000的行,且查看过滤后的数据的行数,

Note:可以类比为Shell中的-

df <- read_csv('pandas120.csv')
df %>%
  filter(salary > 10000) %>%
  dim(.) %>%
  .[1]

.的另一种含义为通配符,但是在此处不做过多赘述。

"[":索引的另一种方式

直接举例说明,

"["(c(123, 12, 3), 1)
# 123
"["(c(123, 12, 3), 2)
# 12

基于glue的格式化输出

1)使用R包glue(集合于tidyverse中),即可以直接理解为C、Pytohn中的格式化输出(e.g. sprintf

2)paste(, collapse=) -> .join()

# library(readr)
# df <- read_csv('600000.SH.csv')
library(glue)
for (i in names(df)){
  if(sum(is.na(df[,'日期'])) != 0){
    res1 <- which(is.na(df[,i]))
    res2 <- paste(res1, collapse = ',')
    print(glue('列名:"{i}", 第[{res2}]行有缺失值'))
  }
}

参考资料

[1] R语言数据处理120题

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容