R语言

R语言笔记Day1 (缺失值的处理—tidyr包+mice包)

2020-01-14  本文已影响0人  养猪场小老板

1、tidyr包主要涉及:

1.1 缺失值的简单补齐

> library(tidyr) 
> library(dplyr)
> # 创建含有缺失值的数据框示例
> x <- c(1,2,7,8,NA,10,22,NA,15)
> y <- c("a",NA,"b",NA,"b","a","a","b","a")
> df <- data.frame(x = x,y = y)
> df
   x    y
1  1    a
2  2 <NA>
3  7    b
4  8 <NA>
5 NA    b
6 10    a
7 22    a
8 NA    b
9 15    a

小技巧

  • 缺失-数字:用均值或中位数替换缺失值;
  • 缺失-字符串:用众数替换缺失值。
接下来

#第一步,计算x的均值和中位数(对缺失值比较敏感)
> x_mean <- mean(df$x, na.rm = TRUE)#TRUE表示去除NA
> x_mean
[1] 9.285714
> x_median <- median(df$x, na.rm = TRUE)
> x_median
[1] 8

#第二步,计算y的众数
> df$y
[1] a    <NA> b    <NA> b    a    a    b    a   
Levels: a b
> table(df$y)
a b 
4 3 
> which.max(table(df$y))
a 
1 
> df$y[which.max(table(df$y))]
[1] a
Levels: a b
> y_mode <- as.character(df$y[which.max(table(df$y))])#众数是字符a
> y_mode
[1] "a"
#如果不是字符串,是整数型变量和因子型变量
#整数型变量,即列表元素个数最多的位置
#a <- which.max(table(df$y)) 
#因子型变量(具体可见table()求每个因子水平的频数)
#a1 <- df$y[which.max(table(df$y))] 

#第三步,#替换数据框df中x和y的缺失值
> df$y
[1] a    <NA> b    <NA> b    a    a    b    a   
Levels: a b
> table(df$y)

a b 
4 3 
> which.max(table(df$y))
a 
1 
> df$y[which.max(table(df$y))]
[1] a
Levels: a b
> y_mode <- as.character(df$y[which.max(table(df$y))])
> y_mode
[1] "a"
> df2 <- replace_na(data = df, replace = list(x = x_mean, y = y_mode))
> df2
          x y
1  1.000000 a
2  2.000000 a
3  7.000000 b
4  8.000000 a
5  9.285714 b
6 10.000000 a
7 22.000000 a
8  9.285714 b
9 15.000000 a

1.2 长形表-变宽形表中的缺失值

举例说明

####新建 长形表
> name <- c('A','A','A','B','B')
> product <- c('P1','P2','P3','P1','P4')
> price <- c(100,130,55,100,78)
> df_long <- data.frame(name = name, product = product, price = price)
> df_long
  name product price
1    A      P1   100
2    A      P2   130
3    A      P3    55
4    B      P1   100
5    B      P4    78

函数长转宽
spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE)

data:为需要转换的长形表
key:需要将变量值拓展为字段的变量
value:需要分散的值
fill:对于缺失值,可将fill的值赋值给被转型后的缺失值

> df_long_expand <- spread(data = df_long, key = product, value = price)                      
> df_long_expand
  name  P1  P2 P3 P4
1    A 100 130 55 NA
2    B 100  NA NA 78
> df_long_expand2 <- spread(data = df_long, key = product, value = price, fill = 0) 
#被转型后的数据框中存在缺失值,如果想给缺失值传递一个指定值的话,就需要fill参数的作用。                    
> df_long_expand2
  name  P1  P2 P3 P4
1    A 100 130 55  0
2    B 100   0  0 78
#新建 宽形表
> name <- c('A','B','C')
> gender <- c('f','f','m')
> province <- c('JS','SH','HN')
> age <- c(18,22,19)
> df_wide <- data.frame(name = name, gender = gender, province = province, age = age)
> df_wide
  name gender province age
1    A      f       JS  18
2    B      f       SH  22
3    C      m       HN  19

实现宽转长
gather(data, key, value, …, na.rm = FALSE, convert = FALSE) 该函数实现宽转长

data:需要被转换的宽形表
key:将原数据框中的所有列赋给一个新变量key
value:将原数据框中的所有值赋给一个新变量value
…:可以指定哪些列聚到同一列中
na.rm:是否删除缺失值


 #默认将所有列存放到key中
> df_wide_gather <- gather(data = df_wide, key = variable,
+                          value = value)
> df_wide_gather
   variable value
1      name     A
2      name     B
3      name     C
4    gender     f
5    gender     f
6    gender     m
7  province    JS
8  province    SH
9  province    HN
10      age    18
11      age    22
12      age    19
 #指定需要被聚为一列的字段
> df_wide_gather2 <- gather(data = df_wide, key = variable, 
+                           value = value, gender, province)
> df_wide_gather2
  name age variable value
1    A  18   gender     f
2    B  22   gender     f
3    C  19   gender     m
4    A  18 province    JS
5    B  22 province    SH
6    C  19 province    HN
> 
> #df_wide_gather2的结果也可以写成
> df_wide_gather3 <- gather(data = df_wide, key = variable, 
+                           value = value, -name) #除name外,其他变量聚成一列
> df_wide_gather3
  name variable value
1    A   gender     f
2    B   gender     f
3    C   gender     m
4    A province    JS
5    B province    SH
6    C province    HN
7    A      age    18
8    B      age    22
9    C      age    19

1.3 列分割与列合并

separate()函数可将一列拆分为多列,一般可用于日志数据或日期时间型数据的拆分,语法如下:
separate(data, col, into, sep = “分隔符”, remove = TRUE,
convert = FALSE, extra = “warn”, fill = “warn”, …)

data:为数据框
col:需要被拆分的列
into:新建的列名,为字符串向量
sep:被拆分列的分隔符
remove:是否删除被分割的列

> id <- c(1,2)
> datetime <- c(as.POSIXlt('2015-12-31 13:23:44'), as.POSIXlt('2016-01-28 21:14:12'))
> df <- data.frame(id = id, datetime = datetime)
> df
  id            datetime
1  1 2015-12-31 13:23:44
2  2 2016-01-28 21:14:12
> # 将日期时间数据切割为日期和时间两列
> separate1 <- df%>%separate(.,col = datetime,into = c("data","time"),
+                            sep = " ",remove = FALSE)
> separate1
  id            datetime       data     time
1  1 2015-12-31 13:23:44 2015-12-31 13:23:44
2  2 2016-01-28 21:14:12 2016-01-28 21:14:12
> # 将日期切割为年月日
> separate2 <- separate1 %>% separate(col = data,into = c("year","month","day"),
+                                     sep = "-",remove = FALSE)
> separate2
  id            datetime       data year month day     time
1  1 2015-12-31 13:23:44 2015-12-31 2015    12  31 13:23:44
2  2 2016-01-28 21:14:12 2016-01-28 2016    01  28 21:14:12
> # 将时间切割为时分秒
> separate3 <- separate2 %>% separate(col = time,into = c("hour","minute","second"),
+                                     sep = ":",remove = FALSE)
> separate3
  id            datetime       data year month day     time hour
1  1 2015-12-31 13:23:44 2015-12-31 2015    12  31 13:23:44   13
2  2 2016-01-28 21:14:12 2016-01-28 2016    01  28 21:14:12   21
  minute second
1     23     44
2     14     12

unite()函数与separate()函数相反,可将多列合并为一列,语法如下:

unite(data, col, …, sep = “_”, remove = TRUE)
data:为数据框
col:被组合的新列名称
…:指定哪些列需要被组合
sep:组合列之间的连接符,默认为下划线
remove:是否删除被组合的列

> #删除原来的日期时间列、日期列和时间列
> separate3 <- separate3[, -c(2,3,7)]
> separate3 
  id year month day hour minute second
1  1 2015    12  31   13     23     44
2  2 2016    01  28   21     14     12
> #将年月日合并为新字段日期
> unite1 <- unite(data = separate3, 'date', sep = '-', year, month, day)
> unite1
  id       date hour minute second
1  1 2015-12-31   13     23     44
2  2 2016-01-28   21     14     12

关于缺失值

首先了解一下处理缺失值的一般步骤:

第一步对缺失值的识别是非常简单的,可以使用is.na()、is.nan()、和is.infinite()函数来鉴别数据集中是否存在缺失;

第二步需要根据实际的场景业务去理解缺失的原因,如敏感数据导致用户不填或网络、机器故障导致数据断层等;

第三步是处理缺失的重要步骤,一般可以通过推理法、行删除法和多重插补法进行处理

下面具体来介绍

一、识别缺失值


> set.seed(1234)
> x1 <- runif(n = 1000, min = 1, max = 15) 
> x2 <- 100*rnorm(n = 1000) + 10 
> x3 <- rt(n = 1000, df = 3) 
> x4 <- rf(n = 1000, df1 = 2, df2 = 3) 
> y <- 2*x1 - 0.3*x2 + 0.6*x3 - 1.2*x4 + rnorm(1000) 
> nonemiss.df <- data.table(y = y, x1 = x1, x2 = x2, x3 = x3, x4 = x4)
> nonemiss.df
               y        x1           x2         x3        x4
   1: -25.642609  2.591848  108.4779968  1.5206970 1.6421182
   2:  52.469333  9.712192 -112.4737876  0.9541739 0.8233494
   3:  -5.777701  9.529846   80.9726218 -0.5763673 1.6377639
   4:  11.783031  9.727312   -0.9219993 -0.8390399 6.3839570
   5: -30.094348 13.052815  188.2607895  0.9603589 0.8097546
  ---                                                       
 996:  -2.531766  1.018322   13.9589562 -0.8615238 0.7856535
 997: -25.752777 11.743963  158.0990197 -2.1667088 0.4541599
 998:  -9.970456  5.479714   66.6660058 -1.1474349 0.1537334
 999: -28.987563 14.412180  188.9580359  0.8767898 1.0181988
1000: -29.245580  3.735566  121.4047851  3.3353688 3.0958502
 #随机将y,x3和x4列的某些观测设为缺失值 
> set.seed(1234)> 
> miss.df <- data.frame(y = y, x1 = x1, x2 = x2, x3 = x3, x4 = x4) 
> miss.df[sample(1:nrow(miss.df), 40),1] <- NA> 
> miss.df[sample(1:nrow(miss.df), 50),4] <- NA 
> miss.df[sample(1:nrow(miss.df), 60),5] <- NA
> nonemiss.df
               y        x1           x2         x3        x4
   1: -25.642609  2.591848  108.4779968  1.5206970 1.6421182
   2:  52.469333  9.712192 -112.4737876  0.9541739 0.8233494
   3:  -5.777701  9.529846   80.9726218 -0.5763673 1.6377639
   4:  11.783031  9.727312   -0.9219993 -0.8390399 6.3839570
   5: -30.094348 13.052815  188.2607895  0.9603589 0.8097546
  ---                                                       
 996:  -2.531766  1.018322   13.9589562 -0.8615238 0.7856535
 997: -25.752777 11.743963  158.0990197 -2.1667088 0.4541599
 998:  -9.970456  5.479714   66.6660058 -1.1474349 0.1537334
 999: -28.987563 14.412180  188.9580359  0.8767898 1.0181988
1000: -29.245580  3.735566  121.4047851  3.3353688 3.0958502
#用mice包中的md.pattern()函数探索缺失值的模式
> install.packages("mice")
> library(mice)
> md.pattern(miss.df)
    x1 x2  y x3 x4    
858  1  1  1  1  1   0
55   1  1  1  1  0   1
45   1  1  1  0  1   1
2    1  1  1  0  0   2
34   1  1  0  1  1   1
3    1  1  0  1  0   2
3    1  1  0  0  1   2
     0  0 40 50 60 150
Rplot.png

上面返回了数据集中缺失值的情况,0表示列中存在缺失值,1表示列中不存在缺失值。

> install.packages("VIM")
> library(VIM)
> aggr(miss.df, prop = FALSE, numbers = TRUE)
Rplot01.png

二、缺失数据处理方法

该方法根据变量间的数学或逻辑关系进行填补或恢复缺失值,如根据某几个变量间的关系来推断缺失值可能的值;根据姓名来推断缺失的性别或根据购买的产品特征推断用户可能所属的年龄段等。

数据集中含有一个或多个缺失值的任意一行都会被删除,一般假定缺失数据是完全随机产生的,且缺失的量仅仅是数据集中的一小部分,可以考虑使用该方法进行缺失值的处理。

该方法是一种基于重复模拟的处理缺失值的方法,它将从一个含缺失值的数据集中生成一组完整的数据集,这些缺失值都是通过蒙特卡洛方法进行替补。替补方法有很多,如贝叶斯线性回归法、自助线性回归法、Logist回归法和线性判别分析法等。

关于多重插补法可以使用mice包中的mice()函数(有关该函数的详细说明可以查看R的帮助文档),该包实现多重插补法并将完整数据集应用到统计模型中的思路如下:

> library(mice) 
> im <- mice(data = miss.df, m = 10, method = 'pmm')
 iter imp variable
  1   1  y  x3  x4
  1   2  y  x3  x4
  1   3  y  x3  x4
  1   4  y  x3  x4
  1   5  y  x3  x4
  1   6  y  x3  x4
  1   7  y  x3  x4
  1   8  y  x3  x4
  1   9  y  x3  x4
  1   10  y  x3  x4
  2   1  y  x3  x4
  2   2  y  x3  x4
  2   3  y  x3  x4
  2   4  y  x3  x4
  2   5  y  x3  x4
  2   6  y  x3  x4
  2   7  y  x3  x4
  2   8  y  x3  x4
  2   9  y  x3  x4
  2   10  y  x3  x4
  3   1  y  x3  x4
  3   2  y  x3  x4
  3   3  y  x3  x4
  3   4  y  x3  x4
  3   5  y  x3  x4
  3   6  y  x3  x4
  3   7  y  x3  x4
  3   8  y  x3  x4
  3   9  y  x3  x4
  3   10  y  x3  x4
  4   1  y  x3  x4
  4   2  y  x3  x4
  4   3  y  x3  x4
  4   4  y  x3  x4
  4   5  y  x3  x4
  4   6  y  x3  x4
  4   7  y  x3  x4
  4   8  y  x3  x4
  4   9  y  x3  x4
  4   10  y  x3  x4
  5   1  y  x3  x4
  5   2  y  x3  x4
  5   3  y  x3  x4
  5   4  y  x3  x4
  5   5  y  x3  x4
  5   6  y  x3  x4
  5   7  y  x3  x4
  5   8  y  x3  x4
  5   9  y  x3  x4
  5   10  y  x3  x4 
> fit <- with(data = im, expr = lm(y ~ x1 + x2 + x3 + x4))
> pooled <- pool(object = fit) 
> summary(pooled)
               estimate    std.error    statistic       df   p.value
(Intercept)  0.01683167 0.0726224265    0.2317696 841.7101 0.8167733
x1           2.00401462 0.0080438273  249.1369521 637.1336 0.0000000
x2          -0.30001081 0.0003660614 -819.5640613 229.3173 0.0000000
x3           0.61370389 0.0197867137   31.0159583 437.1691 0.0000000
x4          -1.20668892 0.0049298963 -244.7696376 532.9739 0.0000000
#以上,给出了线性模型在填补缺失值后的数据集的返回结果。
为了比较,同样将缺失数据集应用到线性模型中:
> lm.fit <- lm(y ~ x1 + x2 + x3 + x4, data = miss.df)
> summary(lm.fit)
Call:
lm(formula = y ~ x1 + x2 + x3 + x4, data = miss.df)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.2114 -0.6782  0.0237  0.6604  3.5705 

Coefficients:
              Estimate Std. Error  t value Pr(>|t|)    
(Intercept)  0.0141706  0.0758362    0.187    0.852    
x1           2.0028833  0.0083552  239.718   <2e-16 ***
x2          -0.2999110  0.0003584 -836.905   <2e-16 ***
x3           0.6179078  0.0200083   30.883   <2e-16 ***
x4          -1.2042557  0.0051187 -235.265   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.9951 on 853 degrees of freedom
  (142 observations deleted due to missingness)
Multiple R-squared:  0.999, Adjusted R-squared:  0.999 
F-statistic: 2.111e+05 on 4 and 853 DF,  p-value: < 2.2e-16
上一篇 下一篇

猜你喜欢

热点阅读