给女朋友写的生统资料_Part6

前面我们已经讲过了在生统课上会用到基本的数据结构以及怎么来提取我们想要的数据,这一部分我们来讲讲数据的清洗。

在生统课上,我们基本上会遇到两种数据结构。一种是我把其叫做宽数据,就比如我们在第五次生统作业中,碰到的第二题的数据。

> test2 <- read.table("rawdata/test2.txt",header = T)

> head(test2)
  control   low middle  high
1   20.79 22.22  28.56 31.93
2   22.91 24.74  28.67 37.94
3   27.21 21.53  25.28 39.76
4   19.34 19.66  30.28 27.94
5   17.85 25.89  23.13 29.65
6   23.79 29.10  23.47 34.23

这种数据列名其实是不同的处理,每一列都对应不同处理下的值。

实际上,这种数据还不能称之为真正意义上的宽数据,这里拿来指代是为了方便与长数据区分。

另一种就是长数据,也就是我上一节翻来覆去提到过的数据结构。其每一行都是一个观测值,列名则是变量名。典型的就是我们在第五次生统作业中,碰到过的第一题的数据。

> test1 <- read.table("rawdata/test1.txt",header = T)
> head(test1)
  yield seed
1   383    1
2   406    1
3   351    1
4   400    1
5   390    1
6   361    1

由于宽数据在线性回归,方差分析等分析中都无法被函数所识别,所以我们首先讲讲如何把宽数据转换成长数据。

gather函数转换

首先介绍的是 tidyr 包的 gather 函数。tidyr 包的安装就是我们之前讲过的方法

install.packages("tidyr")

有点建议大家直接装 tidyverse 包,这是个各种包的合集,里面还包括了 ggplot2 等。不过有可能安不上 tidyverse , 如果安装有问题,欢迎大家在下面提出问题。

gather 函数的使用非常方便,你只需要指定你转换后的 key 那列的列名,value 那列的列名,以及你需要转成长数据的那几列。我们以 test2 为例。

# 加载包
library(tidyr)

# 使用gahter
> test2_long <- gather(test2, key = "Treatment_dose", value = "survive_time",control, low, middle, high)
> head(test2_long)
  Treatment_dose survive_time
1        control        20.79
2        control        22.91
3        control        27.21
4        control        19.34
5        control        17.85
6        control        23.79

gather 函数你需要输入参数为

  • 第一个参数是你的数据集

  • 第二个参数是你新构建的关键列的名称(该列的内容由原先数据集的列名组成)

    名字自己取,像我这里就取名为"Treatment_dose"

  • 第三个参数是新构建的数值列的名称

    名字还是自己取,我这里取名为"survive_time"

  • 后面的几个参数都是你要用来构建关键列的那几个列名

    这里就是control, low, middle, high,即原来的几个列名。

key 和 value 大家可能还是比较懵逼,但对于我们普通的生统数据,不需要太过于纠结其意义。

gather用法在转换的时候还要考虑uniq key的问题,但我们生统的数据应该也不需要考虑这一点。

也有人提到过用 reshape2 包的 melt 函数,或者基本包 transform 函数来转换。但我觉得没有 gather 这个函数直观,简单。还有,gather 转换的时候对于不等长数据的支持也比较好。就比如我们在第五次生统作业的第三题,药物 1 和 2 有 15 只小鼠,药物 3 只有 10 只老鼠。如果只是单纯地按我们之前的做法读入数据框,就会报错。

> test3 <- read.table("rawdata/test3.txt",header = T)
Error in scan(file = file, what = what, sep = sep, quote = quote, dec = dec,  : 
  line 11 did not have 3 elements

就是因为3列数据不等长,所以R才会报错。这时候,我们就可以设置一个参数

> test3 <- read.table("rawdata/test3.txt",header = T,fill = T)
> test3
   med1 med2 med3
1    40   50   60
2    10   20   30
3    35   45  100
4    25   55   85
5    20   20   20
6    15   15   55
7    35   80   45
8    15  -10   30
9    -5  105   77
10   30   75  105
11   25   10   NA
12   70   60   NA
13   65   45   NA
14   45   60   NA
15   50   30   NA

然后就可以顺利地读入了,而且也可以顺利地用gather函数来整理成长数据。

gather(test3,key = "different_med", value = "weight", med1,med2,med3)

会发现NA还是存在,但我们同样可以设置一个参数

gather(test3,key = "different_med", value = "weight", med1,med2,med3,na.rm = T)

这样,就顺利地转换成我们需要的格式了。

基本包转换

其实,宽数据到长数据的转换,不一定需要特殊的包的函数,也可以用最基本的方法。尽管最基本的方法有些麻烦,但对于提高自己的数据转换能力还是很有帮助的。

rbind和cbind

在使用基本函数转换前,我们先来介绍两个我们以后可能会用到的函数,rbindcbind。rbind是纵向合并,cbind是横向合并。具体操作我们来看一个例子

> data1 <- data.frame(A1 = sample(1:10,3),
+                     A2 = sample(1:10,3),
+                     A3 = sample(1:10,3))
> data1
  A1 A2 A3
1  3  6  2
2  7  9  5
3  5 10  4
> data2 <- data.frame(B1 = sample(10:20,3),
+                     B2 = sample(10:20,3),
+                     B3 = sample(10:20,3))
> data2
  B1 B2 B3
1 15 17 14
2 13 14 11
3 17 15 12

> rbind(data1,data2)
Error in match.names(clabs, names(xi)) : 
  names do not match previous names
> cbind(data1,data2)
  A1 A2 A3 B1 B2 B3
1  3  6  2 15 17 14
2  7  9  5 13 14 11
3  5 10  4 17 15 12

可以看到rbind需要两个数据框有同样的变量(同样的列名),cbind则需要两个数据框的行数是一样的。

rbind尽管需要两个数据框有同样的变量,但顺序不一定要一样,比如

> data3 <- data.frame(A1 = sample(10:20,3),
+                     A3 = sample(10:20,3),
+                     A2 = sample(10:20,3))
> data3
  A1 A3 A2
1 10 12 14
2 11 20 20
3 15 14 19
> rbind(data1,data3)
  A1 A2 A3
1  3  6  2
2  7  9  5
3  5 10  4
4 10 14 12
5 11 20 20
6 15 19 14

这里data1和data3的列名是一样的,但顺序是不一样的,但rbind还是可以合并。

关于rbind和cbind,《R语言实战》4.9也有提到,大家可以去看看

数据转换

介绍完了rbind和cbind,我们就可以来转换数据框了。我用test2做例子

> test2
   control   low middle  high
1    20.79 22.22  28.56 31.93
2    22.91 24.74  28.67 37.94
3    27.21 21.53  25.28 39.76
4    19.34 19.66  30.28 27.94
5    17.85 25.89  23.13 29.65
6    23.79 29.10  23.47 34.23
7    22.60 18.93  28.88 32.63
8    18.53 18.64  29.62 29.13
9    23.23 26.39  24.82 39.62
10   20.14 25.49  34.64 36.15
11   26.71 20.43  22.29 28.85
12   19.36 22.69  29.22 24.07
13   17.22 29.67  25.63 29.29
14   24.13 20.36  35.12 35.24
15   25.85 22.74  32.32 36.13

宽数据转换成长数据,本质上就像堆积木一样。你把每一列的数据拿出来,变成一块积木,然后你就一层层地堆起积木,最后就形成了长数据。是不是感觉特别像rbind干的事情?没错,我们这里就用rbind来构建长数据。

control <- data.frame(Treatment_dose = rep("control",15),
                      survive_time = test2$control)
low <- data.frame(Treatment_dose = rep("low",15),
                      survive_time = test2$low)
middle <- data.frame(Treatment_dose = rep("middle",15),
                      survive_time = test2$middle)
high <- data.frame(Treatment_dose = rep("high",15),
                      survive_time = test2$high)
rbind(control,low,middle,high)

大家可能是一遍遍地打了以上的代码,机智的小伙伴可能还是复制粘贴的,然后把变量名改一下。不过,实际上我们可以用函数来解决这些重复操作的问题。函数这一部分就留待后面讲了。

双因素ANOVA的数据格式整理

在第五次生统作业的最后一题,我们需要考虑的是双因素ANOVA分析。但word文件里面的表格却不是一个双因素ANOVA的格式。让我们来看看如何利用上面讲过的内容,把它变成一个能让 aov 读入的双因素AONVA。

首先复制粘贴A1,A2,A3三列数据到txt文件中,然后读入R中。

> test4 <- read.table("rawdata/test4.txt",header = T)
> head(test4)
     A1    A2    A3
1 282.1 296.7 300.1
2 264.2 318.0 307.5
3 274.2 295.3 294.2
4 276.4 292.8 312.0
5 283.7 304.5 300.2
6 288.0 305.9 292.6

然后转换成长数据框

test4_long <- gather(test4, key = temperature, value = weight, A1, A2, A3)

但这样还不够,这里只有单因素,即饲养温度这一列的信息,还没有饲料的信息。所以我们要自己加上一列饲料的信息。

feed <- c(rep("B1",10),rep("B2",10))
test4_data <- cbind(feed,test4_long)
head(test4_data)

> head(test4_data)
  feed temperature weight
1   B1          A1  282.1
2   B1          A1  264.2
3   B1          A1  274.2
4   B1          A1  276.4
5   B1          A1  283.7
6   B1          A1  288.0

这样就变成了双因素的ANOVA格式,可以顺利让aov函数读入了。

> test4_aov <- aov(weight ~ feed * temperature, data = test4_data)
> summary(test4_aov)
                 Df Sum Sq Mean Sq F value   Pr(>F)    
feed              1    127     127   1.589    0.213    
temperature       2   9080    4540  56.809 5.22e-14 ***
feed:temperature  2     17       9   0.108    0.897    
Residuals        54   4316      80                     
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容