作者简介

Dwzb , R语言中文社区专栏作者,厦门大学统计专业学生。

知乎专栏:https://zhuanlan.zhihu.com/Data-AnalysisR

因子型数据是R语言中非常重要的一种数据类型,主要用于分组。本文主要分为两个部分:怎样用R语言从技术层面上对因子型数据进行处理;因子型数据的用途。前者我们将分别使用基础函数和forcats包进行讲述,后者只列出我目前想到的几个方面,以后想到其他的会再往里面补充。

本文目录如下

  • 基础函数

  • forcats包

  • factor的使用

    • 分组计算、统计分析与绘图

    • 一个标签汇总问题

    • 将定序变量转化为哑变量

基础函数

针对因子型数据,我们一般需要用到两种变化

  • 更改level标签名

  • 更改level顺序

我们先使用基础函数实现

(f1 <- factor(c(1,3,5,4,7))) # levels 中只有出现过的
# [1] 1 3 5 4 7
# Levels: 1 3 4 5 7
(f2 <- factor(c(1,3,5,4,7), levels=1:10)) # 指定有哪些levels
# [1] 1 3 5 4 7
# Levels: 1 2 3 4 5 6 7 8 9 10
factor(c(1,3,5,4,7), levels=1:10, labels=letters[1:10]) # 给各个levels命名
# [1] a c e d g
# Levels: a b c d e f g h i j
f2[, drop=T] # 去掉未出现过的levels# 下面对原有的factor进行变化
# 使用levels函数更改level标签名
levels(f1) # 查看f1的levels有哪些
# [1] "1" "3" "4" "5" "7"
levels(f1)[1] <- "x" # 修改第一个level为x,level和向量内容都跟着改变了
f1
# [1] x 3 5 4 7
# Levels: x 3 4 5 7
levels(f1)[2] <- "x" # 将一二两个level合并成一个x
f1
# [1] x x 5 4 7
# Levels: x 4 5 7
levels(f1)[4] <- "x" # 注意这时改变的是新的f1的第4个,即对应7的level
f1
# [1] x x 5 4 x
# Levels: x 4 5# 修改levels顺序,经常用于数据框中一列factor的自身变化
(f1 <- factor(c(1,3,5,4,7))) # 默认按照数字大小顺序排列
f1 <- factor(f1, levels=rev(f1)) # 将原来levels颠倒,不改变向量内容
f1
# [1] 1 3 5 4 7
# Levels: 7 4 5 3 1# 注意下面这种写法
(f1 <- factor(c(1,3,5,4,7)))
levels(f1) <- rev(levels(f1))
f1
# [1] 7 5 3 4 1
# Levels: 7 5 4 3 1
# 变化的是标签名,没有真正改变顺序

forcats包更方便地处理factor,其实就是使用基础包中的函数,实现一些特定的功能,封装成一个包,让人们需要用的时候可以简单地调用,不用自己再编写函数了。

其中的函数分为如下几类

1.修改levels顺序的函数,向量内元素不变
fct_relevel 指定某个level移动到特定位置
fct_inorder 按照第一次出现的次序排列
fct_infreq 按照出现的频率排列
fct_reorder 和 fct_reorder2 作用在一个数据框中的一列factor上,他们的排序要依赖其他列的值
fct_shuffle 随机排序
fct_rev 倒序
fct_shift 实现前后移动,滚动变化2.变换levels名称的函数
fct_anon 用有规律的数字表示
fct_collapse 对应指定更改,主要用于多个合并成一个
fct_recode 手动更改
fct_lump 将出现次数较少的设置为"other"
fct_other 将指定的 level 设置成"other"
fct_relabel 在原有基础上进行修改3.其他函数
fct_c 将两个factor结合
fct_count 数每一个 level 的数量
fct_unique 让每一个level只有一个
fct_drop 去掉一些levels(下面三个更一般的函数,上面这些函数都有着特定的功能,基本上都是调用下面这三个函数实现的)
lvls_reorder 更改level顺序
lvls_revalue 整体更改level名称
lvls_expand 增加一个level

因为这个包只涉及到比较简单的使用,所以下面很多代码是直接从帮助文档中扒下来的

1.修改level顺序的函数使用

# 改变levels顺序
library(forcats)
library(ggplot2)
f <- factor(c("a", "b", "c", "d"))
fct_relevel(f) # 查看原本的f
fct_relevel(f, "c") # c移动到第一位
fct_relevel(f, "b", "a") # b a 移动到前两位
fct_relevel(f, "a", after = 2) # a往后移动两位
fct_relevel(f, "a", after = Inf) # a移动到最后,常用语把像“不知道"z这样的移到最后f <- factor(c("b", "b", "a", "c", "c", "c"))
fct_inorder(f) # 按照第一次出现的次序排列
fct_infreq(f) # 按照出现的频率排列# 按照每一组Sepal.Width的均值从小到大排列
boxplot(Sepal.Width ~ fct_reorder(Species, Sepal.Width, median), data = iris)
boxplot(Sepal.Width ~ fct_reorder(Species, Sepal.Width, median, .desc=T), data = iris) # 从大到小
# 按照每一组time的最后一个值,对应的weight的大小顺序排列
chks <- subset(ChickWeight, as.integer(Chick) < 10)
chks <- transform(chks, Chick = fct_shuffle(Chick))ggplot(chks, aes(Time, weight, colour = fct_reorder2(Chick, Time, weight))) +geom_point() +geom_line() +labs(colour = "Chick")# 随机排序
f <- factor(c("a", "b", "c"))
fct_shuffle(f)
fct_shuffle(f)# 倒序
f <- factor(c("a", "b", "c"))
fct_rev(f)# 前后移动,滚动变化
fct_shift(f) # 第一项放到最后
fct_shift(f, 2) # 前两项放在最后
fct_shift(f, -1) # 最后一项移到最前面

2.修改level标签的函数使用

f <- factor(c("b", "b", "a", "c", "c", "c"))
fct_anon(f)
fct_anon(f, "x")
fct_collapse(f, "x"=c("a","b"), "y"="c")
fct_collapse(f, "x"=c("a","b")) # 只改变一部分也可以x <- factor(rep(LETTERS[1:9], times = c(40, 10, 5, 27, 1, 1, 1, 1, 1)))
x %>% table()
x %>% fct_lump() %>% table()x <- factor(letters[rpois(100, 5)])
x
table(x)
table(fct_lump(x))# Use positive values to collapse the rarest
table(fct_lump(x, n = 4)) # 保留4个最多的level,其他的进入other
table(fct_lump(x, prop = 0.1)) # 保留数量超过10%的level# Use negative values to collapse the most common
table(fct_lump(x, n = -3)) # 保留最少的3个
table(fct_lump(x, prop = -0.1)) # 保留数量少于10%的
fct_lump(x, n = 6, ties.method = "max") # 更换计算方法
# 有这些种选择:ties.method = c("min","average", "first", "last", "random", "max")
table(fct_lump(x, n = 4, other_level = "another")) # 更改替换名称# 将指定的level设置成other
x <- factor(rep(LETTERS[1:9], times = c(40, 10, 5, 27, 1, 1, 1, 1, 1)))
fct_other(x, keep = c("A", "B")) # 保留这两个
fct_other(x, drop = c("A", "B")) # 把这两个变成other# 手动更改
x <- factor(c("apple", "bear", "banana", "dear"))
fct_recode(x, fruit = "apple", fruit = "banana")
fct_recode(x, NULL = "apple", fruit = "banana") # 移除level,向量对应位置变成NA# 在原有基础上进行修改
x <- factor(c("apple", "bear", "banana", "dear"))
f <- function(i){paste(i,1:4,sep="")
}
fct_relabel(x,f)

3.其他函数

fa <- factor("a")
fb <- factor("b")
fab <- factor(c("a", "b"))# 多个factor结合成一个
c(fa, fb, fab) # 变成了一个向量
fct_c(fa, fb, fab)
fct_c(list(fa, fb, fab)) # 或者这样# 对每一个level计数
f <- factor(c("b", "b", "a", "c", "c", "c"))
fct_count(f)# 将多个factor结合到一个list中
fs <- list(factor("a"), factor("b"), factor(c("a", "b")))
fs # 直接转化的list各自levels不一样
fct_unify(fs) # 结合之后levels统一了# 唯一化
unique(f)
fct_unique(f) # 向量中元素按照level的顺序排列f <- factor(c("a", "b"), levels = c("a", "b", "c"))
f
fct_drop(f) # 默认将没有对应值的level去掉fct_drop(f, only = "a") # 如果a不对应则去掉,其他的不要管
fct_drop(f, only = "c")
fct_drop(f, only = c("a","c")) # 在这个向量里面的元素如果有不对应的,就去掉,其他不要管f <- factor(c("a", "b", "c"))
lvls_reorder(f, c(2,3,1)) # 原来第二个放在第一个,原来第三个放在第二个,原来第一个放在最后
lvls_revalue(f, c("apple", "banana", "carrot"))
lvls_expand(f, c("a", "b", "c", "d"))

因子型数据的使用

1.分组计算、统计分析与绘图

library(data.table)
library(ggplot2)
df <- data.table(a = 1:20,b = sample(1:20,20),c = rep(1:5,4))# 分组计算,以均值为例
df[, mean(b), by=c]
df[, mean(b), by=factor(c)]
# 上面这种分组计算是否转化成因子型其实都可以,但是在有的特定统计分析中,如果不转化为因子型就会输出错误的结果
x1 = c(-0.01, 0.15, 0.25, -0.90, 0.86)
x2 = c(11.14,  9.56, 10.33,  8.45,  9.59)
x3 = c(0.77, 0.03, 1.96, 3.24, 2.40)
x = c(x1, x2, x3)
grps =rep(1:3, each=5)summary(aov(x~grps)) # 得到错误的结果
summary(aov(x~factor(grps))) # 正确的做法# 分组绘图,以条形图为例
ggplot(df,aes(a,b)) + geom_line(aes(color=factor(c))) # 这个也必须转化为因子型

2.一个标签汇总问题

比如我们拿到了一个数据集,有3个人列出自己喜欢的软件,但是数据格式不是很理想,我们要将其转化为我们想要的表格形式,具体如下

library(data.table)
library(magrittr)
ori_df <- data.table(name = c("a","b","c"),like = c("R|python", "python|C", "Java|C|Ruby"))
ori_df
#    name        like
# 1:    a    R|python
# 2:    b    python|C
# 3:    c Java|C|Ruby# 想得到这样的形式
#    name        like R python C Java Ruby
# 1:    a    R|python 1      1 0    0    0
# 2:    b    python|C 0      1 1    0    0
# 3:    c Java|C|Ruby 0      0 1    1    1

上面like这列数据,我们肯定是先要用strsplit拆分字符串,然后对每一个进行table统计(这只是一个例子,可以扩展到其他方面上的使用,比如一个人一段时间看过的电影类型汇总,这样就可能出现重复的,所以用table统计次数填入这个矩阵中)。这时出现了一个问题,就是对于每一个人,table只能统计出现过的软件,他们会的还都不一样,难以汇总在一起。这时就想到我们可以将其转化为factor,设定levels是所有的这些软件,再统计个数,没有出现过的就会为0,然后合并起来就好了。代码如下

(u <- strsplit(ori_df$like,"\\|") %>% unlist %>% unique)f <- function(x){unlist(strsplit(x,"\\|")) %>% factor(levels=u) %>%table
}
ori_df[,(u):=transpose(lapply(ori_df$like, f))][]

插一个题外话(和factor无关),这样的数据还可以转化为如下形式来处理

# 想得到这样的形式
#    name        like      1      2    3
# 1:    a    R|python      R python   NA
# 2:    b    python|C python      C   NA
# 3:    c Java|C|Ruby   Java      C Ruby
df1 <- as.data.frame(tstrsplit(ori_df$like,"\\|"))
colnames(df1) <- 1:3
cbind(ori_df,df1)

3.将定序变量转化为哑变量

思路如下:我们创建一个全是0的矩阵,再将应该改为1的索引位置赋值为1. 寻找索引位置的方法:将矩阵看成一个向量,接受一个索引而不是2个,然后将定序变量转化为数字1234加入计算,这个转化的过程最简单的就是转化为因子型再用unclass转化为数值型向量

class.ind <- function(cl)
{n <- length(cl)cl <- as.factor(cl)x <- matrix( 0,  n ,  length(levels(cl)) )x[(1:n) + n*(unclass(cl)-1)] <- 1dimnames(x) <- list(names(cl), levels(cl))x
}
# 测试
x <- c("a","a","b","b","c","c")
class.ind(x)

下面我们把这部分补充完整(虽然和factor也没什么关系)。我们需要在数据框中去除原来的这一列数据,再把新得到的数据去掉一列以防止多重共线性,最后将二者合并在一起,代码如下

library(data.table)
# 配合data.table包使用
# 将数据框和那一列的字符串输入,即可得到新的数据框
# 结果返回哑变量中去除的列名,以及去除一个哑变量再合并之后的数据框,同时打印出去除了的哑变量名字
classdf <- function(dt, x){cl <- class.ind(dt[[x]])print(colnames(cl)[1])cbind(dt[,-x,with=F], cl[,-1])
}
df <- data.table(a=1:3,b=2:4,c=3:5)
new <- classdf(df,"a")
new# 改进函数,接受一个字符串向量,同时对多列进行相同处理multiclassdf <- function(dt, xs){l <- lapply(dt[, xs, with=F], class.ind)print(unlist(lapply(l, function(x) colnames(x)[1])))Reduce(function(x,y) cbind(x,y[,-1]), l, dt[, -xs, with=F])
}
multiclassdf(df, c("a","b"))

文末彩蛋

推荐rstudio脚本文件分块索引的技巧

  • 在 .R 文件中,# part1--------- 单独成行,将代码按照层级分块,点击前面的三角符号,可以将这一部分代码折叠起来,同时可以在脚本区域下边栏上查看分块目录 part1 part2 等,快速定位所要寻找的内容

  • 在 .rmd 文件中,# ## 是分级标题,也可以在下边栏查看目录。```{r} 这种代码块也会出现在下方目录之中,代码块也可以命名,方便快速查找 ```{r part1}

  • 这些块都可以折叠成一行,再配合快捷键 alt + 上下,可以实现整个块的移动

往期回顾

R数据处理|基础篇(一)

R数据处理|基础篇(二)

R数据处理|data.table篇(一)

R数据处理|data.table篇(二)

R数据处理|data.table篇(三)

R深入 | 数据类型

R | 基础绘图

R|ggplot2(一)|一个完整的绘图流程

R|数据处理|merge数据详解

公众号后台回复关键字即可学习

回复 爬虫            爬虫三大案例实战  
回复 Python       1小时破冰入门

回复 数据挖掘     R语言入门及数据挖掘
回复 人工智能     三个月入门人工智能
回复 数据分析师  数据分析师成长之路 
回复 机器学习      机器学习的商业应用
回复 数据科学      数据科学实战
回复 常用算法      常用数据挖掘算法

R|数据处理|因子型数据相关推荐

  1. R语言因子型数值转数值型

    一直觉得只要是数字,不管是什么类型的,都可以通过as.numeric()函数转换为对应的numeric类型的数字,例如 x<-"123",x为character类型,而as. ...

  2. 入门必学 | R语言数值型、字符型及因子型数据之间的差异与转换

    字符型.数值型及因子型数据之间的转换 数据类型的基本知识 不同数据类型之间的差异 数值型与字符型或因子型绘图时的差异 数值型与因子型和字符型的模型构建时的差异 三种数据类型之间进行转换    常用的三 ...

  3. r语言中mpg数据_R语言数据分析系列之五

    R语言数据分析系列之五 本节来讨论一下R语言的基本图形展示,先来看一张效果图吧. 这是一张用R语言生成的,虚拟的wordcloud云图,详细实现细节请參见我的github项目:https://gith ...

  4. R语言入门第二集 实验一:R 语言数据结构、数据导入与数据处理

    R语言入门第二集 实验一:R 语言数据结构.数据导入与数据处理 一.资源 R语言基本数据结构练习和数据的导入和处理对象常用函数练习--东北大学大数据班R语言实训第一次作业" R(4)求解数据 ...

  5. c程序:定义函数areaZ,功能是求圆锥体积。在主函数中输入半径r和高h,调用函数areaZ求体积,并在主函数中输出圆锥的体积,其中变量r,h均为double型数据。(公式v=h*3.14*r2/3)

    /*定义函数areaZ,功能是求圆锥体积.在主函数中输入半径r和高h,调用函数areaZ求体积,并在主函数中输出圆锥的体积,其中变量r,h均为double型数据.(公式v=h*3.14*r2/3)*/ ...

  6. R语言基本介绍 | 数据科学、Rstudio介绍、快捷键操作、R代码常见命令、数据类型、示例代码等等

    一.数据科学 数据科学:计算和统计技术的综合应用,用于解决一些真实世界中的问题. 计算:获得结果 统计:分析和建模 真实世界:机器学习.AI 数据科学Data Science = 统计+数据处理+机器 ...

  7. R语言——数据格式和数据读取

    R语言--数据读取之详解 福尔·摩斯曾说过:"数据,数据,没有数据的推理是罪恶!" 不过比起有意思的统计分析,数据的导入与导出显得十分的无趣,但是不得不说统计分析的数据导入与导出是 ...

  8. R语言-因子的构造-factor函数

    参考内容:教程一, 非数值型变量(类别变量和顺序变量)在R语言中称为因子,也称为因子型变量.因子型变量内的所有非重复值,被称为因子水平(levels). 创建因子 在R语言中可以使用factor()函 ...

  9. R:数据分析-----汽车数据可视化

    目录 一.获取汽车燃料效率数据 1.下载数据集 2.保存数据集的字段信息 二.将汽车燃料效率数据导入R 三.探索并描述燃料效率数据 四.分析汽车燃料效率数据随时间的变化情况 五.研究汽车的品牌和型号 ...

最新文章

  1. 这里有最全的k8s初学者指南!!!
  2. asp.net core选项配置的研究
  3. python基础代码库-python基础:一个非常简单且详细的多线程代码
  4. AL2018届校招笔试——自然语言处理
  5. JPA中的@MappedSuperclass
  6. r生成html文件,从R中的许多html文件创建一个语料库
  7. 【前端规划】来看看我整理的这一份专属技术知识图谱吧~
  8. 字段不显示 继承_Springboot Shiro页面按钮显示、路径越权访问题
  9. OpenCV for Android开发环境Win7平台搭建(转)
  10. DDR2与DDR的区别
  11. 白话关于API与SDK的区别
  12. EVE-NG模拟器综合
  13. ws2812b灯带容易坏_树莓派控制WS2812B灯带 - Python
  14. Linux中ffmpeg批量压缩音频
  15. webstorm配置vue模板 webstorm快速生成vue模板
  16. matlab newton插值,(最新整理)Newton插值法
  17. 狂神JAVA博客MySQL_狂神说SpringBoot08:整合Druid
  18. ubuntu server 7.04(10.04版也行) 挂载移动硬盘
  19. 破解webshell方法~
  20. 一文彻底讲透@Async注解的原理和使用方法

热门文章

  1. 九华山《高僧传奇(上)》
  2. STM32G0+EMW3080+阿里云实现单片机WiFi智能联网功能(一)EMW3080实现和PC之间的串口通讯
  3. 实时公交小程序开发有哪些功能和优势?
  4. 2021年ACP敏捷认证考哪些内容?
  5. Json与Java对象的相互转换
  6. Effective C++ --条款1
  7. 浅谈数字媒体艺术中的技术应用-4-技术路线和学习地图
  8. 可以用思维导图iMindMap做什么
  9. ideal怎么刷新文件夹
  10. VC中加载GIF格式动态图片的详细方法!