因子型数据是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)] <- 1
dimnames(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 + 上下,可以实现整个块的移动
往期回顾
公众号后台回复关键字即可学习
回复 爬虫 爬虫三大案例实战
Python
1小时破冰入门
回复 数据挖掘 R语言入门及数据挖掘
回复 人工智能 三个月入门人工智能
回复 数据分析师 数据分析师成长之路
回复 机器学习 机器学习的商业应用
回复 数据科学 数据科学实战
常用算法
常用数据挖掘算法
本文由R语言中文社区 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Creative Curve
Allen Gannett / Knopf Doubleday Publishing Group / 2018-6-12
Big data entrepreneur Allen Gannett overturns the mythology around creative genius, and reveals the science and secrets behind achieving breakout commercial success in any field. We have been s......一起来看看 《The Creative Curve》 这本书的介绍吧!