当前位置:   article > 正文

R语言数据处理——基础篇 data.frame基本操作

data.frame

R语言数据处理——基础篇 data.frame基本操作

打算用两篇博客来记录下平时使用R语言进行数据处理、绘图遇见的一些问题。第一篇首先介绍下使用data.frame处理数据的常用操作,第二篇总结下使用ggplot2绘图时常用的一些操作。每篇博客在基础介绍完后总结下自己遇到过的问题,不定时补充。

data.frame的创建

可以从文件和构造函数创建data.frame。

  • 可以使用以下几个函数从csv、excel文件创建data.frame。
函数名包含库
read.csv-
read.csv2-
read_excelreadxl
read_xlsreadxl
read_xlsxreadxl
read.csv(file, header = TRUE, sep = ",", quote = "\"", 
	dec = ".", fill = TRUE, comment.char = "", ...)

read.csv2(file, header = TRUE, sep = ";", quote = "\"", 
    dec = ",", fill = TRUE, comment.char = "", ...)  
  • 1
  • 2
  • 3
  • 4
  • 5

主要参数包括
file:文件路径。注意使用相对路径时,是相对工作目录,工作目录绝对路径使用getwd()查看,以及使用setwd()设置。
header:是否将文件第一行当作行名,默认为TRUE。选FALSE时依然会读取第一行,只不过会自动生成默认行名,使用rowname()<-更改即可。
sep:csv文件的分隔符,默认为",",常见的分隔符包括","、" “、”;"。
quote:字符的表示方式,默认用" “包围引号。
dec:小数点的表示方式,默认为”.";
fill:当各列变量数不一样时是否填补,默认为TRUE。注意补充的类型与读取文件后,程序判定的列变量类型有关,如果列变量是数字会用NA,如果是字符则会用"",不会用NULL填补也不能用is.null()检查。
comment.char:指定读取文件中的注释字符,注释字符及其后不会被读取。

library(readxl)

read_excel(path, sheet = NULL, range = NULL, col_names = TRUE, 
    col_types = NULL, na = "", trim_ws = TRUE, skip = 0, 
    n_max = Inf, guess_max = min(1000, n_max), progress = readxl_progress(), 
    .name_repair = "unique") 

read_xls(path, sheet = NULL, range = NULL, col_names = TRUE, 
    col_types = NULL, na = "", trim_ws = TRUE, skip = 0, 
    n_max = Inf, guess_max = min(1000, n_max), progress = readxl_progress(), 
    .name_repair = "unique") 

read_xlsx(path, sheet = NULL, range = NULL, col_names = TRUE, 
    col_types = NULL, na = "", trim_ws = TRUE, skip = 0, 
    n_max = Inf, guess_max = min(1000, n_max), progress = readxl_progress(), 
    .name_repair = "unique") 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这里给个自己R读取excel所有工作表的写法,

file = 'data.xlsx'
sheets <- excel_sheets(file)
data <- data.frame()
i <- 1
for (time in sheets) {
  data_once <- read_xlsx(file, 
                         sheet=time,
                         col_names=F,
                         # range = ,根据数据需要和效率确定读取范围
                         # 参数值见cell-specification: Specify cells for reading
                         )
  data.once$x <- seq(1, length(rownames(data_once))
  data = rbind(data, data.once)
  
  print(i)
  i = i + 1
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 常用的data.frame构造与辅助函数
    可以使用几个相同长度的向量构造data.frame。
time <- 1:3
value1 <- c(1, 2, 2)
value2 <- c(2, 0, 2)

data <- data.frame(time, value1, value2)
  • 1
  • 2
  • 3
  • 4
  • 5

创建的data.frame data为

	 time	value1	value2
1		1		 1		 2
2		2		 2		 0
3		3		 2		 2
  • 1
  • 2
  • 3
  • 4

当需要创建具有一定规则的向量时,除了使用循环还可以使用以下几个辅助函数:
使用:创建连续数字的序列,

vector.1 <- 1:5
# 1 2 3 4 5
  • 1
  • 2

当然也可以使用小数,但是创建的序列步长为1。

vector.2 <- 0.1 2.2
# 0.1 1.1 2.1
  • 1
  • 2

更改步长可以用seq(from, to, step)

vector.3 <- seq(0.1, 2.2, 0.5)
# 0.1 0.6 1.1 1.6 2.1
  • 1
  • 2

有时候可能需要创建按规则重复的向量,使用rep(vector, repeat_times)

vector.4 <- rep(1:3, 2)
# 1 2 3 1 2 3
  • 1
  • 2

从辅助函数得到的临时变量创建data.frame时就可以指定列名,不用创建后再更改

data.frame("serial" = 1:4, "value" = rep(c(1, 0), 2))
#   serial value
# 1      1     1
# 2      2     0
# 3      3     1
# 4      4     0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

数据访问、条件筛选与删除

以前述data为例。

> data
	 time	value1	value2
1		1		 1		 2
2		2		 2		 0
3		3		 2		 2
  • 1
  • 2
  • 3
  • 4
  • 5

数据访问

访问行、列、指定行列数据都可以从索引或行名、列名访问

# 从索引访问第2行
data[2,]
#   time value1 value2
# 2    2      2      0

# 从列名访问列
data$value1
# 1 2 2

# 从行名访问行
data["3", ]
#   time value1 value2
# 3    3      2      2

# 访问指定的其他行列
# 只能通过索引操作,不能从行名、列名操作,行名、列名都是字符类型,不支持-操作符,如data[-"2",]、data[,-"value1"]
data[-2,]
#   time value1 value2
# 1    1      1      2
# 3    3      2      2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

获取行名、列名

rownames(data)
# "1" "2" "3"
colnames(data)
# "time"   "value1" "value2"

# 通过赋值可以对行名、列名进行更改
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

数据筛选

常用的筛选包括:

  • 逻辑运算符<>!===
  • 多个条件,|&。注意别写成||&&
  • 包含在指定向量的子向量%in%

data.2为例。

data.2 <- data.frame("time" = rep(1:3, 2),
	"value" = c(data$value1, data$value2),
	"type" = gl(2, 3, labels = c("value1", "value2")))
  • 1
  • 2
  • 3
> data.2
  time value   type
1    1     1 value1
2    2     2 value1
3    3     2 value1
4    1     2 value2
5    2     0 value2
6    3     2 value2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

筛选value = 0的数据。需要注意筛选操作获得的是基于行或列的一系列布尔值,别忘了","。

data.2[data.2$value == 0, ] # 注意别忘了","
#   time value   type
# 5    2     0 value2
  • 1
  • 2
  • 3

筛选value值在向量[0, 1]中的数据

data.2[data.2$value %in% c(0, 1), ]
#   time value   type
# 1    1     1 value1
# 5    2     0 value2
  • 1
  • 2
  • 3
  • 4

筛选time < 3且time > 1的数据

data.2[data.2$time > 1 & data.2$time < 3, ]
#   time value   type
# 2    2     2 value1
# 5    2     0 value2
  • 1
  • 2
  • 3
  • 4

删除

基于上述访问、筛选操作后重新赋值即可实现删除操作。

  • 根据索引删除选定行、列
    删除第2行
data.remove_row_2 <- data.2
data.remove_row_2  <- data.remove_row_2[-2,]
  • 1
  • 2
> data.3
  time value   type
1    1     1 value1
3    3     2 value1
4    1     2 value2
5    2     0 value2
6    3     2 value2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 按条件筛选
data.remove_type1 <- data.2[data.2$type != "value1",]
  • 1
> data.remove_row
  time value   type
4    1     2 value2
5    2     0 value2
6    3     2 value2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 筛选操作后默认生成的行名可能从1开始或不连续,重新给行名赋值就行
data.rename_row <- data.remove_type1
rownames(data.rename_row) <- seq(nrow(data.rename_row))
  • 1
  • 2
> data.rename_row 
  time value   type
1    1     2 value2
2    2     0 value2
3    3     2 value2
  • 1
  • 2
  • 3
  • 4
  • 5

使用gather()进行data.frame数据格式转换

前面用到的data、data.2具有不同的形式,前者可能更易读,但是大多数数据处理包和绘图包使用第二种形式。这时可以用tidyr包中的gather()进行数据格式的转换。

> data
	 time	value1	value2
1		1		 1		 2
2		2		 2		 0
3		3		 2		 2
  • 1
  • 2
  • 3
  • 4
  • 5
> data.2
  time value   type
1    1     1 value1
2    2     2 value1
3    3     2 value1
4    1     2 value2
5    2     0 value2
6    3     2 value2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

函数参数如下,
gather(data, key = "key", value = "value", ..., na.rm = FALSE, convert = FALSE, factor_key = FALSE)
从data到data.2如下操作即可

library(tidyr)
gather(data, value, type, -time)
#   time   type value
# 1    1 value1     1
# 2    2 value1     2
# 3    3 value1     2
# 4    1 value2     2
# 5    2 value2     0
# 6    3 value2     2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

简要说下可能的实现方式。

  1. 从data到data.2需要对value1、value2两列进行一个转置,再把不进入转置操作的time列对应复制到转置后的数据即可。
  2. 所以首先选择需要变形的data.frame,接着区分需要转置的列和不需要转置的列,不需要转置的用"-"操作放到其他参数后就行。
  3. gather()函数会将原数据转置区的列名一行视为主键列key,其余行、列的数据依次对应主键变成value列,我们只需要给新的key、value列命名即可。

给个自己的数据当例子。

depthsensor4336291120
110.97849830.95595060.97633690.96595610.9796494
210.98978780.98114740.99641730.98947870.9758862
120.92869280.93184750.95162430.93613770.9450460
220.93761160.95341880.95788160.94560950.9516801
130.95251890.96171890.96257060.97339910.9672283
230.96819600.98693300.98583270.97170860.9831383

每个深度有3个传感器,一共有两个深度,测量间隔30 s共测量了120 s。
选择非转置列,重命名新key、value列即可。

library(tidyr)
data.example <- read.csv("text.csv")
gather(data.example, time, value, -depth, -sensor)
#    depth    sensor time     value
# 1      1         1    4 0.9784983
# 2      2         1    4 0.9897878
# 3      1         2    4 0.9286928
# 4      2         2    4 0.9376116
# 5      1         3    4 0.9525189
# 6      2         3    4 0.9681960
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

常见问题

列、行名包括"X"、“V”

读取数据时如果原文件列名、行名为数字,读取后data.frame可能会在数字前加上前缀"X"、“V”。

  • 规则的数据直接利用辅助函数更改列名、行名、指定列。
data.file <- read.csv("data_file.csv")
#   v1 v2 V3
# 1  1  2  3
# 2  1  2  3
# 3  1  2  3

colnames(data.file) <- c(1:length(colnames(data.file))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 数据不规则,例如为测试数据值时,进行字符串处理即可,取字符第二位到最后一位。
data.file2 <- read.csv("data_file2.csv")
#    time X0 X10 X15 X17 X18
# 1 value  1   2   3   4   5

colnames(data.file2) <- c(colnames(data.file2)[1],
	sapply(sapply(colnames(data.file2)[-1],substr,2,10), as.numeric))
#    time 0 10 15 17 18
# 1 value 1  2  3  4  5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

内部sapply对指定范围取子字符串,从第2位到第10位(最大位即可,想写函数复用使用max(nchar(colnames(a)))得到最长字符数),外部sapply转为数值类型。


P.S.
使用Python pandas时经常弄混两个的函数,考虑写在一起比较还是用一样的模板分开写,欢迎建议。
有问题指出、补充欢迎评论区交流。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/66078?site
推荐阅读
相关标签
  

闽ICP备14008679号