• R语言数据分析 听课笔记第二部分 执具


    R语言数据分析 听课笔记第二部分 执具

    R的知识体系

    R语言的知识体系:基础编程+数据对象
    基础编程:R的运行机制及编程环境,代码的组成,扩展包,函数的调用,基本控制流,编写函数,二元操作符,泛型函数。
    数据对象:向量,因子,矩阵,数组,列表,数据框。

    R专用IDE:RStudio

    先安装R,然后再安装Rstudio。

    1. 从CRAN 下载R并安装
    2. 下载Rstudio并安装
      建议将R安装在C://Program Files文件夹下,安装完之后将library文件夹权限设置为完全读写
      Rstudio建议下载免安装版(即zip文件),可解压缩在D盘适当位置,并且注意解压路径不能含有中文。
      (但是根据我的经验,我还是觉得下载安装版的.exe比较好,因为用免安装版时,发现打开project之后不能自动加载出对应工作目录的文件)

    R编程,站在巨人的肩膀上

    R编程,用别人的包和函数讲述你自己的故事。

    重点是如何找到需要的包,推荐一下四种方法:

    1. 搜索引擎搜索, bing, baidu
    2. 逛论坛找答案,Stackoverflow,搜索时,最好在问题后面加一个[R],就表示是R语言问题
    3. SOS扩展包,使用findFn()函数进行模糊查找。
    4. 按图索骥,Task views,或许是最正统的,可以鸟瞰R的全景,比如task, machine learning and stastics learning.
    5. 专注于某个领域,日积月累。R的真正精通,需要不断积累总结。

    caret 包,是机器学习与数据挖掘中强烈推荐的,其中支持的分类回归模型达200多种。分类回归的模型,其体量就是数以百计的。

    对于某个扩展包中的具体某个函数的使用,利用好帮助文档。比如,对于c()函数,

    ?c

    R基础编程:控制流

    任何复杂的逻辑都是三种结构

    • 顺序结构:代码一行一行逐行执行(四则运算,逻辑运算,均可以向量化运算)
    • 分支结构:
    • 循环结构

    分支结构:

    if(){
    
    }else if(){
    
    } else{
    
    }
    
    ifelse(condition, 
           yes, 
           no)
    

    all()函数、any()函数,就是向量化的逻辑运算函数

    需要注意的是,else 必须要与上一个花括号在同一行,else语句不能单起一行。

    注意,if中的条件判定结果只能是一个标量,如果传入一个向量的逻辑向量,那么R会只取向量的第一个值。

    循环结构,R中有三种循环

    for,枚举型循环

    while,有条件的循环

    repeat,无条件循环,

    两种语句实现控制循环,break, next

    斐波那契序列的实现: 1,1,2,3,5,8,13,21,34,55...

    # 列举前16个序列数,可以使用for 循环
    n_fib <- 16
    fib <- numeric(n_fib)
    fib[1:2] <- c(1,1)
    for(i in 3:n_fib){
        fib[i] <- fib[i-1] + fib[i-2]
        show(fib[i])
    }
    
    # 求1000以内的斐波那契序列,此时不确定要枚举多少,所以使用while循环
    fib <- c(1,1)
    while(sum(tail(fib, 2)) < 1000){
        fib <- c(fib, sum(tail(fib, 2)))
    }
    
    # repeat循环,需要定义终止条件,表示直到满足某个条件时break
    fib <- c(1,1)
    repeat{
        if((sum(tail(fib, 2))>= 1000){
            break
        }
        fib <- c(fib, sum(tail(fib, 2)))
    }
    

    再说向量化

    尽量不要使用显示循环

    能用向量化运算的,尽量用向量化运算

    # 举例比较1亿数字加和的时间,向量化运算和for循环
    x <- 1:1e8
    y <- 2:(1e8+1)
    z <- integer(1e8)
    system.time(z <- x + y, gcFirst = TRUE)
    ## 显示耗时0.45s
    
    # use for loop
    system.time({
        for (i in 1:1e8){
            z[i] <- x[i] + y[i]
        }
    }, gcFirst = TRUE)
    ## 显示耗时11.7s
    

    记住,只要串行模式不是必须的,就是说下一轮的循环不受上一轮的影响,那么就应该使用并行运算。

    R里面的并行作业

    • 向量化函数
    • split - apply - combine 数据处理模式: 如apply函数族,以及tidyverse::group_by + summerize函数
    • 专门的并行主题, task views High-performance and parallel computing with R

    R基础编程:函数I

    事不过三的原则

    只要代码粘贴达到3次时,就应该写一个函数进行实现。因为反复的拷贝粘贴,造成的忘记修改某一个参数时,这种非语法错误的代码很难调试。

    编写函数

    fun_name <- function(arg1, arg2 = default, ...){
        #注释
        表达式
        return(value)
    }
    
    
    • R里面一切皆是对象,对象通过赋值来产生,函数也不例外。
    • 函数声明的关键字是function,function 的返回值就是函数。
    • 参数列表是以逗号分隔,函数主体可以是任何合法的R表达式
    • 若没有return语句,最后一个表达式的值就作为返回值。
    • 以fun_name(arg1, arg2, ...)的形式调用函数。
    • 如果不跟(),就是显示函数这个变量的内容

    位置参数 和 名义参数

    frm <- function(name, frm = 'Beijing'){
        cat(name, ' is from ', frm)
    }
    

    R中既有位置参数, 也有名义参数。

    特殊的参数,比如对于c()函数, sum()函数,打开这两个函数的信息,可以参数看到是 ...

    my_func <- function(...){
        cat("The second argument is ", ..2) # ..2就是表示提取第二个参数,可以依次类推
        dot_args <- list(...)# 通过list来捕捉任意参数
        message("
    The sum is", sum(dot_args[[1]], dot_args[[5]]))
    }
    my_func(1, 'arg2', 3,4,5,6,7,8)
    # 输出结果
    # The second argument is arg2
    # The sum is 6
    

    还有一些熟悉的函数,作为函数的二元操作符, 加减乘除,%in% 等都是函数

    自己定一个二元操作符函数,求直角三角形的斜边长度(a, b为直角边,c为斜边)

    %ab2c% <- function(a,b){
        sqrt(sum(a^2, b^2))
    }# 没有return语句,就是返回最后一行语句的值
    3 %ab2c% 4 
    # 输出结果
    # 5
    

    到这里,也可以理解purr包中的管道操作符 %>%,其实它也是一个二元操作符函数。

    注意的是,二元操作符函数,在查询其函数使用文档时,需要用引号将其引起来,比如?"+", ?"-"。

    R基础编程:函数II

    泛型函数

    因为在使用R时,比如plot()函数时,你发现传入不同的数据类型,会生成不同的结果,也就是同一个函数,在接收不同的对象时,有不同的函数行为,这就是泛型函数。

    泛型函数,其实是一组函数。在定义时可以明显发现是同一个interface,但是其实是一组函数,使用了分发机制。

    编写泛型函数,理解泛型函数的定义和调用过程

    interface <- function(x, y){
        message("Single interface")
        UseMethod("particular", y)
    }
    particular.classA <- function(x, y){
        message("Different behavior: classA")
    }
    particular.classB <- function(x, y){
        message("Different behavior: classB")
    }
    particular.default <- function(x, y){
        message("Different behavior: default")
    }
    
    x <- 1:10
    y <- 1:20
    class(y) <- "classA"# 给y贴上标签- classA
    interface(x, y)
    #> Single interface
    #> Different behavior: classA
    
    class(y) <- "classB" # 给y贴上标签- classB
    interface(x, y)
    #> Single interface
    #> Different behavior: classB
    
    class(y) <- "classC" # 给y贴上标签- classC
    interface(x, y)
    #> Single interface
    #> Different behavior: default
    
    class(y) <- NULL # 或者撕掉y 的标签
    interface(x, y)
    #> Single interface
    #> Different behavior: default
    

    从上面就可以看出,同一个interface接口,可以有不同的行为。并且可以看出,R中的类,并不是说数据的存储类型,而只是一种标签。

    重新审视 + 这个函数

    > methods("+")
    [1] +.Date   +.POSIXt
    see '?methods' for accessing help and source code
    
    > library(ggplot2)
    > methods("+") # 同一条语句,不同的结果
    [1] +.Date   +.gg*	+.POSIXt
    see '?methods' for accessing help and source code
    
    

    所以可以,进一步看 “+.gg” 这个函数的内容。

    类似于“+.gg”, 可以定义自己的+

    "+onlyFirst" <- function(a, b){
        return(a[1] + b[1])
    }
    a <- 1:5
    a + 6:10
    #> [1] 7 9 11 13 15
    
    class(a) <- "onlyFirst" # 给a贴上一个类标签, onlyFirst
    a + 6:10
    #> [1] 7 # 输出结果就只有7了,因为这个函数只计算第一个元素的加和
    
    

    递归函数

    再看斐波那契序列,可以通过递归的思想来实现。层层递进,逐层回归。

    递归函数,都一个触底的点。

    fib <- function(n){
        if(n ==1){
            return(1)
        } else{
            return(c(fib(n-1),sum(tail(fib(n-1), 2)))) # 这里没有对n=2的情况进行触底,是因为tail函数在调用时,如果只有一个值,tail(fib, 2) 就直接返回这个值了
        }
    }
    fib(10)
    
    

    R数据对象:向量与因子

    R数据对象,分为三组,六类。

    单一属性特征:向量与因子进行存储

    数据的材质:也是6种。参考文档,?atomic

    logical, 逻辑型

    integer, 如1L, 300L,整型

    numeric, 1, 3.14, 双精度型

    complex, 1+2i

    character, 'hello, world'

    raw(原始字节数据,如b0, ac, d0, c2, b2, a8).

    向量

    创建向量:c()函数,不能有混合类型,否则会强制进行转换为同一类型。

    不存在包含向量的向量,R会一律拆包展开。

    创建向量: vector("numeric", 8) ,实现知道数据类型和向量长度进行创建

    > (x1 <- vector("numeric", 8))
    [1] 0 0 0 0 0 0 0 0
    > (x2 <- numeric(8))
    [1] 0 0 0 0 0 0 0 0
    > (x3<- character(8))
    [1] "" "" "" "" "" "" "" "" #默认是空字符
    > (x4 <- vector(len = 8))
    [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
    > (x5 <- logical(8))
    [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE # FALSE 就是默认的0
    
    # 等差数列, seq()
    > seq(from = 1, to = 20, by = 2)
     [1]  1  3  5  7  9 11 13 15 17 19
    > seq(from = 20, to = 1, by = -2)
     [1] 20 18 16 14 12 10  8  6  4  2
    > seq(from = 1, to = 20, len = 10) # 设置长度个数len 参数
     [1]  1.000000  3.111111  5.222222  7.333333  9.444444 11.555556 13.666667
     [8] 15.777778 17.888889 20.000000
    # 显然,此时的by = (to - from)/(len -1) 
    
    # 产生随机数向量,sample()
    sample(10)
    set.seed(2012) #设定随机数种子
    sample(10) # 无放回抽样
    re_sample <- sample(1:100, 100, replace = TRUE) # 有放回抽样
    
    
    

    访问向量

    [] 来指定

    1. 采用1 ~ n的正整数来指定,n为向量长度。下标可以重复,顺序可以变。
    2. 采用负整数,反向选出某些元素,就是丢掉某些元素
    3. 逻辑下标,要求提供的逻辑下标向量是和要查看的向量的长度是一样的。
    4. 通过元素的名称访问响应的子集

    向量的基本操作

    向量排序:

    sort()函数, 返回的是排序后的向量,可以设置decreasing = TRUE

    order()函数,order函数,返回的是下标。

    rev()函数,向量逆序

    并且c(),向量,其实就是数学中的向量,它满足数学向量的运行和运算含义。

    因子

    测量的尺度:

    类型 量化尺度 举例 数学性质 R数据对象
    定类 是否相同 性别、人种 等于 不等于 无序因子 (因子)
    定序 比较大小 等级、规模 大于 小于 有序因子(因子)
    定距 确定差别 温度、时刻 加 减 数值向量(向量)
    定比 确定比例 长度、薪资 乘 除 数值向量(向量)

    向量用于存储数值变量(定距 定比)

    因子用于存储类别变量(定类 定序)

    第一种创建因子方法: factor()函数

    xb <- c('F','M','F','M')
    xb <- factor(xb)
    xb <- factor(xb, levels = c('M','F','Lost'))
    typeof(xb)
    # integer # 说明内存中存的还是整型,并且其实就是1, 2 等整数。
    nlevels(xb)
    levels(xb)
    
    

    因子在内存中存储的是整数,见下面的示例

    > number_factors <- factor(c(10,20,20,20,10))
    > mean(number_factors)
    [1] NA
    Warning message:
    In mean.default(number_factors) : 参数不是数值也不是逻辑值:回覆NA
    > mean(as.numeric(number_factors))
    [1] 1.6
    > as.numeric(number_factors)
    [1] 1 2 2 2 1
    > mean(as.numeric(as.character(number_factors)))
    [1] 16
    > mean(as.numeric(levels(number_factors)[number_factors]))
    [1] 16
    > levels(number_factors)
    [1] "10" "20"
    > levels(number_factors)[number_factors]
    [1] "10" "20" "20" "20" "10"
    
    

    因子,可以创建为有序的。有序的因子就可以比较大小

    > score <- factor(c('Best', "Good", "Bad"), ordered = TRUE)
    > score[1] > score[2]
    [1] FALSE
    > score[1] < score[2]
    [1] TRUE
    > score[1]
    [1] Best> score <- factor(c('Best', "Good", "Bad"), ordered = TRUE)
    > score[1] > score[2]
    [1] FALSE
    > score[1] < score[2]
    [1] TRUE
    > score[1]
    [1] Best
    Levels: Bad < Best < Good
    > score <- factor(c('Best', "Good", "Bad"), ordered = TRUE, levels = c("Bad","Good","Best")) # 这个levels如果不设置的话,R 其实是默认按照编码顺序排的,比如字母表或者拼音
    > score[1] > score[2]
    [1] TRUE
    > score[1]
    [1] Best
    Levels: Bad < Good < Best
    Levels: Bad < Best < Good
    
    

    第二种创建因子方法:R中通过cut()函数分箱,对数据向量进行分组,来实现创建因子。以成绩划分为五分制进行经典示例。数据分箱 + 最小区间为闭区间 + 左开右闭 + 有序因子 + 标签

    > yw <- c(94, 87, 92, 91, 85, 92)
    > # 数据分箱 + 最小区间为闭区间 + 左开右闭 + 有序因子 + 标签
    > yw5 <- cut(yw, breaks = c(0, (6:10)*10), include.lowest = TRUE, right = FALSE, ordered_result = TRUE, labels = c("不及格","及格","中","良","优"))
    > yw5
    [1] 优 良 优 优 良 优
    Levels: 不及格 < 及格 < 中 < 良 < 优
    
    

    R数据对象:矩阵与数组

    对观测对象的多个属性同时进行记录(多变量)

    若这些数据是同质的,宜采用矩阵作为一个整体进行存储。

    矩阵,是二维的

    数组是多维的。

    matrix(c()) 按照列优先的方式进行填充。如果数据要按行进行填充,则设置byrow = TRUE.

    子集的访问依然是通过[],由于矩阵是二维的,所以需要','分别指定行和列。

    diag(3)生成单位矩阵

    solve()函数,可以解方程组

    强烈推荐R与matlab对照的一个pdf,基本上matlab中可以实现的功能,R中都可以实现。

    r-matlab

    数组

    矩阵本质上是二维的数组,数组一般就是说高纬数组了,一般三维数组使用频率最高。

    彩色图像,就是RGB,就是存储为三维数组的。其实图片的操作,本质上都是数组的操作。

    操作数组就可以实现,对图像的操作,比如更改图像颜色,“图像泛黄处理”,以及在特定区域添加马赛克。

    R数据对象:数据库与列表

    数据的属性不是同质的。

    列表

    列表,本质就是对象的有序集合。列表最为灵活,最具有包容性,对所包含的对象没有限制,可以是不同的类型,不同的长度。

    创建列表list()

    访问列表:$, [], [[]]. 单个方框号提出来的数据,依然是一个列表。两个方框号才进入包装箱的内部。

    更改列表元素,也是直接赋值就可以。

    删除一个列表元素,就是对该列表元素赋值NULL 就可以。

    对列表的每一个组成部分,执行某种操作,使用的是lapply()函数。lapply()函数返回的还是一个列表,所以可以再用unlist()将列表结果展平。这两步操作,可以直接用sapply()函数,来实现。

    数据框

    是最核心的R语言中的数据对象类型,绝大部分的时间,就是把既有的数据转换成数据框,进而以数据框为基础,开展数据探索和数据建模。

    数据框,是R中最美好的数据对象。

    数据框形式上是矩阵,本质上是列表。

    与数据库关系表,excel中的sheet相近。

    列是变量,属性,特征,维度

    行是记录,观测值,是数据空间中的一个点

    创建数据框

    data.frame()

    因为本质上是列表,所以列表的访问方式,对data.frame都适用。不过一般用$,或者单方括号访问。还有矩阵的访问方式,对数据框也都适用。

    矩阵中的cbind(), apply(),也可以对数据框使用。

    查看数据, head(), tail(), str(), summary()

    机器学习是一个举三反一的过程,所以一般嘛,就是训练集70%,测试集30%,二者三七开。

    人人都爱tidyverse

    tidyverse 是一个扩展包的套装

    library(tidy)即加载下下述八个包。

    ggplot2, dplyr, tidyr, readr, purr, tibble, stringr, forcats

    管道操作符,

    lhs %>% rhs

    lhs 是value, rhs是函数

    表达式 用法
    x %>% y f(x)
    x %>% f(y) f(x, y)
    y %>% f(x, .) f(x, y)
    z %>% f(x, y, arg = .) f(x, y, arg = z)
    x %>% f %>% g %>% h h(g(f(x)))

    更多用法参见 ?magrittr:: %>%

    dplyr: data manipulation

    select()

    mutate()

    filter()

    arrange()

    summarize(),一般和group_by函数一起使用

    cjb %>%
    	mutate_at(vars(bj, xb, wlfk), factor) %>%
    	mutate(zcj = rowSums(.[4:12])) %>%
    	arrange(desc(zcj)) %>%
    	tail(n = 2)
    
    

    如果想让上述修改生效,一种方法是上述代码中,第一个%>%替换为%<>%,第二种方法是,在开始的第一行加一句赋值语句。如下代码所示(cjb 就是成绩表的例子,bj 班级,xb 性别,wlfk 文理分科):

    cjb %<>%
    	mutate_at(vars(bj, xb, wlfk), factor) %>%
    	mutate(zcj = rowSums(.[4:12])) %>%
    	arrange(desc(zcj)) %>%
    	tail(n = 2)
    # 上述代码和下面的代码等价
    cjb <- cjb %>%
    	mutate_at(vars(bj, xb, wlfk), factor) %>%
    	mutate(zcj = rowSums(.[4:12])) %>%
    	arrange(desc(zcj)) %>%
    	tail(n = 2)
    
    

    对行的过滤操作,filter()函数

    # 显示语文成绩不及格的同学
    cjb %>%
    	filter(yw < 60)
    
    # 显示有一科成绩不及格的同学
    cjb %>%
    	filter_at(vars(4:12), any_vars(.<60))
    
    

    分组统计功能

    基于已有的分组变量,或者基于新生成的分组变量

    # 举例,分组看一下男生 女生的总成绩有无差别
    cjb %>%
    	filter(zcj != 0) %>%
    	group_by(xb) %>%
    	summarize(count = n(),
                 max = max(zcj),
                 mean = mean(zcj),
                 min = min(zcj))
    
    # 举例,另外一种分组的情况,需要做数据的长宽变化的情况,就是看所有学生的不同科目的成绩有没有差别,就是按科目进行汇总统计
    # 长宽变化,使用tidyr中的gather() 和spread() 函数
    cjb %>%
    	filter(zcj != 0) %>%
    	gather(key = ke_mu, value = cheng_ji, yw:sw) %>%
    	group_by(ke_mu) %>%
    	summarize(max = max(cheng_ji),
                 mean = mean(cheng_ji),
                 median = median(cheng_ji),
                 min = min(zcj)) %>%
    	arrange(mean)
    
    

    最美不过数据框

    数据框,是R中数据预处理的目标。

    发现数据背后的规律,很大程度上就是发现数据框背后的规律。

    最主要的关联、分类、聚类分析都蕴藏在数据框的数据中。

    一切都是关系结构,关系表几乎可以上升为一个数学概念。

  • 相关阅读:
    LeetCode 169. Majority Element
    Object-c block块
    Object-c动态特性
    Object-c基础(2)
    Object-c基础
    LeetCode171:Excel Sheet Column Number
    LeetCode242:Valid Anagram
    LeetCood8:String to Integer
    理解qsort 中的 cmp
    google goble cache
  • 原文地址:https://www.cnblogs.com/songbiao/p/12423121.html
Copyright © 2020-2023  润新知