基础知识
其优点
- 有大量统计建模,机器学习,可视化的相关包,快速实现你的想法
- 很前沿,因为统计学和机器学习的研究人员会为最新的研究成果而开发一个包
- 对函数式编程很支持
缺点:
- 使用者大多数不是程序员,很多是为了解决一些问题而编写的,代码可能存在很多缺点。
- 在各种包中,甚至基础 R 语言中,都存在不一致的情况。 你面对的是已经进化了超过 20 年的 R 语言。 R 语言的学习很困难,因为我们需要记住很多特殊的情况。
- R 语言不是特别快的编程语言,写得很差 R 语言代码可以变得非常缓慢。 R语言也非常消耗内存。
读完你会获得什么:
- 生产高质量代码的能力
- 了解原理,理解复杂的数据类型,并且学习对他们进行操作的做好方法。对函数的工作有更好的理解,认识和使用R语言的四种面向对象系统。
- 理解什么是函数式编程,以及为什么函数式编程是数据分析有利的工具,
- 理解元编程
- R语言那些操作很慢,那些操作很消耗内存,能够有很好的直觉,你将知道如何使用分析工具来确定性能的瓶颈,以及学习足够的C++知识,以便将R语言转化为等价的C++代码。
- 轻松阅读大多数R语言代码,熟悉术语,并且能够评判别人的代码。
元技术
有两种元技术(Meta-techniques)非常有利于提高R语言程序员的能力,阅读源代码以及采取科学的思路。
阅读你经常使用的函数和包的源代码。发现一些有价值的内容,可以尝试模仿。
科学的思维方式就是,如果你不理解某种事物,那就首先提出一个假设,然后设计一些实验,接着运行他们,最后记录结果。
推荐阅读:
《Structure and Interpretation of Computer Programs》
《Concepts, Techniques and Models of Computer Programming》
《The Pragmatic Programmer》
数据结构
五种数据结构
使用str()
可以查看数据结构
几个问题:
- 除了包含的数据以外,向量的三个性质是什么?
- 四种常见的原子向量类型是什么?两种罕见的是什么
- 属性是什么,如何存储属性
- 原子向量与列表有什么不同?矩阵和数据框有什么不同
- 列表也可以是矩阵吗?数据框能把矩阵作为一列数据吗?
向量
最基本的结构是向量,其有两种形式,原子向量与列表。他们有三种相同的属性。
类型:typeof
他是什么
长度:length
它包含多少元素
属性:attributes
额外的任意元素
他们的不同在于元素类型,原子向量中的元素必须是同一类型的,列表的元素可以是不同类型的。
注:is.vector()并不能测试一个对象是不是向量。 相反,仅当对象是除了名字以
外,不包含其它属性时,它才返回 TRUE。 所以,请使用 is.atomic(x) || is.list(x)来
测试一个对象是不是向量。
原子向量
四种常见的原子向量类型:逻辑,整数,双精度,字符类型。不讨论两种罕见类型,复数类型,raw类型
原子箱里那个通常使用c()
来建立。其是单词combine 的缩写
type_of来测试类型或者使用is开头的一系列函数。
强制转换,因为原子向量都必须是同一类型的,当你试图合并不同类型的数据时,将向最灵活的类型进行强制转换。 以灵活程度排序,从小到大依次为:逻辑、整数、双精度浮点数和字符。
当逻辑向量被强制转换为整数或者双精度浮点数类型时,TRUE 将变成 1,FALSE
将变成 0。 这项特性使得逻辑向量与 sum()和 mean()函数结合使用时,变得非常
方便。
列表
创建列表用list
列表有时被称为递归向量,因为一个列表可以包含其它列表: 这使得它们从根本
上不同于原子向量。
对列表调用 typeof()函数,得到的结果是列表。 你可以用 is.list()来测试列表,或
者使用 as.list()来强制转换成列表。 你可以使用 unlist()把一个列表转换为原子向
量。 如果列表中的元素具有不同的类型,那么 unlist()将使用与 c()相同的强制转
换规则。
列表用来建立 R 语言中的许多更加复杂的数据结构。 比如,数据框和线性模型对象都是列表:
属性
所有向量可以拥有任意多个附加属性,附加属性用来存取与该对象相关的元数据。属性可以看作是已经命名的列表。
属性可以通过strr
进行一个个访问,也可以使用attributes
函数一次性进行访问。
structure()函数返回一个带有被修改了属性的新对象:
structure(1:10, my_attribute = "This is a vector")
#> [1] 1 2 3 4 5 6 7 8 9 10
#> attr(,"my_attribute")
#> [1] "This is a vector"
但是,有三种重要的属性不会丢失:
- 名字(name),一个字符向量,用来为每一个元素赋予一个名字,将在第
2.2.0.1 节介绍。 - 维度(dimension),用来将向量转换成矩阵和数组,将在第 2.3 节介绍。
- 类(class),用于实现 S3 对象系统,在第 7.2 节介绍。
这些属性中的每一个都有特定的访问函数来存取它们的属性值。 当访问这些属性
时,请使用 names(x)、class(x)和 dim(x),而不是 attr(x, "names")、attr(x, "class")
和 attr(x, "dim")。
你可以使用 unname(x)创建没有名字的新向量,或者使用 names(x) <- NULL 去掉名字。
因子
因子构建与整数向量之上,,并带有了两个属性:
- 类(class)
- 水平(level)
有时,当从文件里直接读取数据框时,你认为某列应该产生数值向量,但是却变
成了因子。 这是由于这一列中有非数值数据造成的,通常,缺失值使用.或者-这样
的特殊符号来表示。 为了避免这个情况,可以先把因子向量转换成字符向量,然
后再从字符向量转换到双精度浮点数向量(这个过程之后,务必检查缺失值!)。
当然,一个更好的方法是从一开始就积极寻找出现问题的原因,并予以修改;在
read.csv()中使用 na.strings 参数来解析缺失值字符,通常会更好。
矩阵与数组
为原子向量添加一个dim属性,可以让它变成多维数组。 数组的一种特例是矩阵,即二维数组。 矩阵在统计学中使用得非常广泛。 高维数组则用得少多了,但是也需要一定的了解。 矩阵和数组是由 matrix()和 array()函数创建的,或者通过使用 dim()函数对维度(dimension)属性进行设置来得到。
length()和 names()在任何维度上都可以使用,而对于矩阵和数组,则有更细分的
函数:
- length(): 对于矩阵,nrow()和 ncol()分别获取行数和列数;对于数组,dim()
获取每个维度。 - names(): 对于矩阵,rownames()和 colnames()分别获取行名和列名;对于数
组,dimnames()获取每个维度的名字。
cbind()和 rbind()函数是 c()函数对矩阵的推广;abind()函数是 c()函数对数组的推
广(由 abind 包提供)。 你可以使用 t()转置一个矩阵;它对数组的推广,则是
aperm()函数。 你可以使用 is.matrix()和 is.array()来测试一个对象是不是矩阵或者
数组,或者查看 dim()函数返回的维度值。 as.matrix()和 as.array()使向量转化为
矩阵或数组变得简单。 向量不是仅有的一维数据结构。 你可以创建单行或者单列
矩阵,也可以创建单维数组。 它们看起来很像,但是行为是不同的。 它们的区别
并不是那么重要,但是当你运行某些函数(比如 tapply()函数常出现这个情况)得到
了奇怪的输出时,你要能想到它们的存在。 同样地,使用 str()可以查看它们的区
别。
数据框
数据框是 R 语言中最常用的存储数据的方式,如果使用得当,可以使数据分析工作变得更轻松 数据框是由等长向量
构成的列表。 它也是二维结构,所以它具有矩阵和列表双重属性。 也就是说,数据框拥有 names()、colnames()和rownames(),尽管 names()和 colnames()对数据框来说是一样的。 数据框的 length()是列表的长度,所以和 ncol()相同;nrow()则得到行数。
使用data.frame
来创建数据框.
测试和强制转换
由于数据框是 S3 类,它是由向量构建而成,所以它的类型反映出向量的特性:它
是列表。 要检查一个对象是不是数据框,可以使用 class()函数或者is.data.frame()
函数:
#> [1] "list"
class(df)
#> [1] "data.frame"
is.data.frame(df)
#> [1] TRUE
你可以使用 as.data.frame()
把一个对象转换成数据框:
- 一个原子向量会创建单列数据框。
- 列表中的每个元素会成为数据框的一列;如果元素的长度不同,则会发生错
误。 - n 行 m 列的矩阵会转换为 n 行 m 列数据框
####### 特殊列
由于数据框是一个包含向量的列表,所以数据框的某个是列表类型是有可能的:
df <- data.frame(x = 1:3)
df$y <- list(1:2, 1:3, 1:4)
df
#> x y
#> 1 1 1, 2
#> 2 2 1, 2, 3
#> 3 3 1, 2, 3, 4
然而,当把列表传入 data.frame()函数时,该函数将试图把列表的每一个元素都放
到单独的一列中,所以,下面的代码会失败:
data.frame(x = 1:3, y = list(1:2, 1:3, 1:4))
#> Error: arguments imply differing number of rows: 2, 3, 4
一种绕开的方法是使用 I()函数,它使得 data.frame()把列表看成一个整体单元: