R|数据处理|因子型数据

栏目: Ruby · 发布时间: 6年前

作者简介

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)] <- 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 + 上下,可以实现整个块的移动

往期回顾

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

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

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

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

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

R深入 | 数据类型

R | 基础绘图

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

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

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

回复 爬虫 爬虫三大案例实战  

Python

1小时破冰入门

回复 数据挖掘  R语言入门及数据挖掘

回复  人工智能 三个月入门人工智能

回复  数据分析师 数据分析师成长之路 

回复 机器学习 机器学习的商业应用

回复  数据科学 数据科学实战

常用算法

常用数据挖掘算法

R|数据处理|因子型数据

本文由R语言中文社区 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。

转载、引用前需联系作者,并署名作者且注明文章出处。

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Foundations of PEAR

Foundations of PEAR

Good, Nathan A./ Kent, Allan / Springer-Verlag New York Inc / 2006-11 / $ 50.84

PEAR, the PHP Extension and Application Repository, is a bountiful resource for any PHP developer. Within its confines lie the tools that you need to do your job more quickly and efficiently. You need......一起来看看 《Foundations of PEAR》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具