数据框塑形——Tidyr vs Reshape

数据框的塑形是学习R语言过程中的一个重要的知识点,是从Excel思维转换成编程思维的重要过程。尽管很多作图函数一个命令就可以让输入数据变成美轮美奂的图,但往往初学者会卡在如何制作符合需要的input data上面。根源原因就是Excel的数据储存思维与R语言有很大不同。很多时候日常记录在Excel里面的数据格式不适合直接用,而在Excel里面“点点点和调调调”又非常违背学习R语言的“懒人精神”。所以为了节省下“点点点和调调调”的枯燥时间,就要花时间学习一下数据塑形。

本文要介绍的2个包3对函数都出自哈德利大神。一般人写包就是只是造个工具,大神直接定义了一种数据转换的思维。直接上表格,用眼睛体会一下表格的“长”和“扁”,省去大段文字描述。

test <- data.frame(geneid = paste0("gene",1:4),
                   sample1 = c(1,4,7,10),
                   sample2 = c(2,5,0.8,11),
                   sample3 = c(0.3,6,9,12))
test

我先不说这个test它是个“扁”表格,因为当我把它变“长”了,就能感受到它的“扁”了。

# 先不用管这里的包和函数,体会表格
library(tidyr)
gather(data = test,
                      key = sample_nm,
                      value = exp,
                      - geneid)

数据框“扁”变“长”就是将所有观测值汇总成了一列,所有变量名也汇总成列。因为R语言数据处理的时候基本都是取列(向量)来用的,具体列里面的元素取哪些,就靠筛选了。所以要变成这样。

reshape2 —— melt & dcast

我盲猜这个包是最先出现的,因为包里面的函数最少,文档里面有这样一句话:

Reshape (hopefully) makes it easy to do what you have been struggling to do with tapply, by, aggregate, xtabs, apply and summarise. It is also useful for getting your data into the correct structure for lattice or ggplot plots.

感觉它就是为ggplot应运而生的。它俩还一起获得了2006年的 John Chambers Award for Statistical Computing奖项。尽管现在用的都是ggplot2了,但这些旧的包和函数都和好用,生命力旺盛着呢。这三对函数之间没有巨大差别,细微之处遇见的比较少,选哪个,顺手就是好的

melt 变长

melt基本语法是:

melt(data,id.vars,measure.vars,variable.name='variable',...,na.rm=FALSE,value.name='value',factorAsStrings=TRUE)

只需要记住前三个变量,后面的都不用管:

  • data:指的你想处理的数据框
  • id.vars:是不想融合的变量,可以是一个也可以是多个(括在向量里)
  • measure.vars:想要融合的变量
  • variable.name & value.name:默认会把融合的变量名储存的列的列名定义为“variable”,而观测值的列名定义为“value”,有了这两个参数,可以在融合时就修改成自己想要的名字。
library(reshape2)
test_melt <- melt(test,id.vars = "geneid",measure.vars = c("sample1","sample2","sample3"))

dcast 变扁

“长”变“扁”用的是dcast()函数,语法是:

dcast(data, formula, fun.aggregate = NULL, ..., margins = NULL,
  subset = NULL, fill = NULL, drop = TRUE, value.var = guess_value(data))

其中需要掌握的是参数formula的格式

rowvar1 + rowvar2 +...  ~  colvar1 + colvar2 +...

按照rowvar,展开colvar。也可以理解为rowvar是不变的,colvar是拆分的

我们试试将变化的数据再恢复。和原始数据比较一下,是一样的。

test_dcast <- dcast(test_melt, geneid ~ variable)
test_dcast
identical(test, test_dcast)

dcast很棒的功能——聚合运算

dcast有一个很棒的功能就是可以在聚合的时候(dcast称为聚合的过程)可以同步对数据执行函数运算。

  • fun.aggregate:用于指定聚合函数,对已聚合的数据执行聚合运算

演示的时候由于test没有相同的分组,所以我们加一列type。

x = test
x$type = rep(c("A","B"),2)
x

可以看到重塑以后的数据对各列按照type进行了均值(mean)计算。

x_melt = melt(x,id.vars = c("geneid","type"),measure.vars = c("sample1","sample2","sample3"))
dcast(x_melt, type ~ variable, mean)

tidyr —— gather & spread

tidyr是哈德利大神的神作tidyverse中的成员。专注数据框整理,除了gatherspread还有许多别的函数。这里只关注这两个函数。

gather 变长

这对函数开始提出了keyvalue的概念。key就是由变量名组成的一列,相当于melt里面的id.vars。value就是观测值,相当于measure.vars。对于不想变化的列,就在列名前面加一个"-"(减号)。

用法是:

gather(data,key = "key", value = "value", ..., na.rm = FALSE, convert = FALSE, factor_key = FALSE)
test_gather <- gather(data = test,
                      key = sample_nm,
                      value = exp,
                      - geneid)
test_gather

spread 变扁

用法是:

spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL)

演示一下test数据,和原始数据比较果然也是一样的。

test_spread <- spread(data = test_gather,
                  key = sample_nm,
                  value = exp)
test_spread
identical(test,test_spread)

注意到spread里面有个fill参数,是处理NA值的,默认是给填上"NA"。

test_na <- test_gather[c(1:2,5:11),]
test_na_re <- spread(data = test_na,
                     key = sample_nm,
                     value = exp)
test_na_re # 赋值为NA
# 也可以填上别的,字符串,一个确定的数字都可以
test_na_fill <- spread(data = test_na,
                     key = sample_nm,
                     value = exp,
                     fill = "AAA")

参数dropgather里面的na.rm一样,就是对于有缺失的观测值是否显示。

meltgather的比较

我们来比较一下meltgather的结果。

colnames(test_melt) <- colnames(test_gather) # 列名不一致先处理一下
identical(test_gather,test_melt)

结果是不一样的,很意外吧。肉眼上是完全看不出来的

test_gather
test_melt

str一下能看出来,数据的格式不一样。gather将汇总的变量名处理成字符型,而melt处理成因子型(即使是在options(stringsAsFactors = FALSE)的大环境下),这样作图的时候就会产生影响,所以个人觉得gather会更好用一些,当需要变因子的时候,再手动调整,也可以自定义因子的顺序。

tidyr —— pivot_longer & pivot_wider

在查看gather帮助文档的时候会发现这个包的状态是“retired”。尽管并不影响我们对这个包的热爱和使用,但好奇心驱使我去查看了文档底下推荐的pivot,然后就看到了大神对自己包的官方吐槽。

For some time, it’s been obvious that there is something fundamentally wrong with the design of spread() and gather(). Many people don’t find the names intuitive and find it hard to remember which direction corresponds to spreading and which to gathering. It also seems surprisingly hard to remember the arguments to these functions, meaning that many people (including me!) have to consult the documentation every time.

他们的用法如下,只保留了重要参数。详细的参见vignette

pivot_longer(
  data,
  cols,
  names_to = "name",
  values_to = "value")

pivot_wider(
  data,
  id_cols = NULL,
  names_from = name,
  values_from = value)

这两对函数和gather & spread没有本质区别,只是让参数“说人话”了,使用起来更友好了一些。所以对应的参数名称是:

gather & spread pivot_X
key names_to
value values_to
key names_from
value values_from

其他资料

另外看到了一篇文章关于tidyr和reshape2的比较。https://rpubs.com/sterding/Reshape2_and_Tidyr

Tidyr vs. Reshape2

  1. They are very similar!
  2. cast() in reshape2 can work on matrix/array, while gather() in tidyr can only work on data.frame.
  3. reshape2 can do aggregation, while tidyr is not designed for this purpose.
  4. colsplit() in reshape2 operates only on a single column while separate() in tidyr performs all the operation at once.
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352