数据框基本操作的常见方法

本文所说的数据框基本操作,主要包括添加新列、数据排列、数据筛选、数据选择和对所有列进行相同操作,针对每一种操作在基础包和dplyr包中使用方法进行了对比介绍。相对基础包的处理方法,dplyr包中的方法除了更加灵活外,处理速度也会大幅度提升。

添加新列

使用的数据companiesData来自于网络,它是苹果、谷歌以及微软等三家公司在2010到2013年3年间的营收与利润数额,其中fy为年份,company为公司名称,revenue为公司营收,profit为公司利润。创建两列:公司所属国家(country),其值为America;利润列(margin),其值等于利润(profit)除以营收(revenue)再乘以100。

fy <- c(2010,2011,2012,2010,2011,2012,2010,2011,2012)  
company <- c("Apple","Apple","Apple","Google","Google","Google","Microsoft",  
"Microsoft","Microsoft")  
revenue <- c(65225,108249,156508,29321,37905,50175,62484,69943,73723)  
profit <- c(14013,25922,41733,8505,9737,10737,18760,23150,16978)  
companiesData <- data.frame(fy, company, revenue, profit)
  • 为列简单创建一个变量名称
companiesData <- data.frame(fy, company, revenue, profit)
companiesData$country <- 'America'
companiesData$margin <- (companiesData$profit / companiesData$revenue) * 100
companiesData
		fy   company revenue profit country   margin
	1 2010     Apple   65225  14013  Aerica 21.48409
	2 2011     Apple  108249  25922  Aerica 23.94664
	3 2012     Apple  156508  41733  Aerica 26.66509
	4 2010    Google   29321   8505  Aerica 29.00651
	5 2011    Google   37905   9737  Aerica 25.68790
	6 2012    Google   50175  10737  Aerica 21.39910
	7 2010 Microsoft   62484  18760  Aerica 30.02369
	8 2011 Microsoft   69943  23150  Aerica 33.09838
	9 2012 Microsoft   73723  16978  Aerica 23.02945
  • 利用transform函数
companiesData <- data.frame(fy, company, revenue, profit)
companiesData <- transform(companiesData,  country = 'Aerica', margin = (profit/revenue) * 100)
companiesData
		fy   company revenue profit country   margin
	1 2010     Apple   65225  14013  Aerica 21.48409
	2 2011     Apple  108249  25922  Aerica 23.94664
	3 2012     Apple  156508  41733  Aerica 26.66509
	4 2010    Google   29321   8505  Aerica 29.00651
	5 2011    Google   37905   9737  Aerica 25.68790
	6 2012    Google   50175  10737  Aerica 21.39910
	7 2010 Microsoft   62484  18760  Aerica 30.02369
	8 2011 Microsoft   69943  23150  Aerica 33.09838
	9 2012 Microsoft   73723  16978  Aerica 23.02945

相对第一种方法,transform可以同时添加多列,书写相对简单,但是利用tranform时,新列必须是原始列的计算,而不能对刚刚建立起来的列进行计算,换句话说上面的第二条语句,如果要写成下面这样是错误的,原因就在于margin.new = margin * 1.2中margin是新生的数据列,而非数据中原有的列。

companiesData <- transform(companiesData,  country = 'Aerica', margin = (profit/revenue) * 100, margin.new = margin * 1.2)
  • dplyr包中的mutate函数

dplyr包可以简单地认为是对plyr包的升级,所以这两个包中的mutate函数有相似的作用。mutate函数很好的解决了transform函数不能解决的问题,即mutate函数,允许新列对刚刚建立起来的列进行计算。所以,对于tansform函数来说,错误的用法。

companiesData <- transform(companiesData,  country = 'Aerica', margin = (profit/revenue) * 100, margin.new = margin \* 1.2)

对于mutate函数来说,是正确的。

library(dplyr)
companiesData <- data.frame(fy, company, revenue, profit)
companiesData <- mutate(companiesData, country = 'Aerica', margin = (profit/revenue) * 100, margin.new = margin * 1.2)
companiesData
		fy   company revenue profit country   margin margin.new
	1 2010     Apple   65225  14013  Aerica 21.48409   25.78091
	2 2011     Apple  108249  25922  Aerica 23.94664   28.73597
	3 2012     Apple  156508  41733  Aerica 26.66509   31.99811
	4 2010    Google   29321   8505  Aerica 29.00651   34.80782
	5 2011    Google   37905   9737  Aerica 25.68790   30.82548
	6 2012    Google   50175  10737  Aerica 21.39910   25.67892
	7 2010 Microsoft   62484  18760  Aerica 30.02369   36.02842
	8 2011 Microsoft   69943  23150  Aerica 33.09838   39.71806
	9 2012 Microsoft   73723  16978  Aerica 23.02945   27.63534

数据排列

数据hflights来自R包hflights,记录的是飞机航班数据信息。

library(hflights) 
  • 利用order函数
# 默认升序排列
hf = hflights[order(hflights$DayofMonth, hflights$Month, hflights$Year), ]
# 降序排列
hflights[order(desc(hflights$ArrDelay)), ]
  • dplyr包中的arrange函数

plyr包中也有具有相似功能arrange函数

require(dplyr)
# 默认升序排列
hf = arrange(hflights, DayofMonth, Month, Year)
# 对列名加 desc() 进行倒序
hf = arrange(hflights, desc(ArrDelay))

数据筛选

数据同样使用自R包hflights的hflights。数据筛选是选择满足符合某些条件的数据行。

# 查看各月数据行,方便下面的结果的确认
table(hlihgts$Month)
		1     2     3     4     5     6     7     8     9    10    11    12 
	18910 17128 19470 18593 19172 19600 20548 20176 18065 18696 18021 19117 
  • 直接选取数据框中满足条件的数据行

满足一个条件;

## 满足数据框hflights中Month列等于1
hf1 = hflights[hflights$Month == 1]
nrow(hf1)
	[1] 18910

两个以上的条件:同时满足(相当于逻辑“且”);

# 这里以两个条件为例
## 例子1:满足数据框hflights中Month列同时等于1和2
hf2 = hflights[c(hflights$Month == 1 & hflights$Month == 2), ]
## 其值等于0,数据框hflights的Month列没有同时等于1,又等于2的数据行
nrow(hf2)
	[1] 0
## 例子2:满足数据框hflights中Month列等于1且DayofMonth列等于2
hf3 = hflights[c(hflights$Month == 1 & hflights$DayofMonth == 2), ]
nrow(hf3)
	[1] 678

两个以上的条件:至少满足其中一个(相当于逻辑“或”)。

# 这里以两个条件为例
## 例子1:满足数据框hflights中Month列同时等于1或2
hf4 = hflights[c(hflights$Month == 1 | hflights$Month == 2), ]
## 其值等于18910(Month = 1) + 17128(Month = 1)
nrow(hf4)
	[1] 36038
## 例子2:满足数据框hflights中Month列等于1或DayofMonth列等于2
hf5 = hflights[c(hflights$Month == 1 | hflights$DayofMonth == 2), ]
nrow(hf5)
	[1] 25764
  • subset函数

满足一个条件;

## 满足数据框hflights中Month列等于1
hf1 = subset(hflights, Month == 1)
nrow(hf1)
	[1] 18910

两个以上的条件:同时满足(相当于逻辑“且”);

# 这里以两个条件为例
## 例子1:满足数据框hflights中Month列同时等于1和2
hf2 = subset(hflights, Month == 1 & Month == 2)
## 其值等于0,数据框hflights的Month列没有同时等于1,又等于2的数据行
nrow(hf2)
	[1] 0
## 例子2:满足数据框hflights中Month列等于1且DayofMonth列等于2
hf3 = subset(hflights, Month == 1 & DayofMonth == 2)
nrow(hf3)
	[1] 678

两个以上的条件:至少满足其中一个(相当于逻辑“或”)。

# 这里以两个条件为例
## 例子1:满足数据框hflights中Month列同时等于1或2
hf4 = subset(hflights, Month == 1 | Month == 2)
## 此时也只有此时,subset函数可以写多个条件
## 这种方法不建议使用
hf4 = subset(hflights, Month == 1, Month == 2)
## 其值等于18910(Month = 1) + 17128(Month = 1)
nrow(hf4)
	[1] 36038
## 例子2:满足数据框hflights中Month列等于1或DayofMonth列等于2
hf5 = subset(hflights, Month == 1 | DayofMonth == 2)
nrow(hf5)
	[1] 25764
  • dplyr包中的fliter函数

plyr包中并没有相似功能的filter函数。

满足一个条件;

require(dplyr)
## 满足数据框hflights中Month列等于1
hf1 = filter(hflights, Month == 1)
nrow(hf1)
	[1] 18910

两个以上的条件:同时满足(相当于逻辑“且”);

# 这里以两个条件为例
## 例子1:满足数据框hflights中Month列同时等于1和2
hf2 = filter(hflights, Month == 1 & Month == 2)
##在filter中,','直接相当于'&'
hf2 = filter(hflights, Month == 1, Month == 2)
## 为了统一,这种方法也不推荐使用
## 其值等于0,数据框hflights的Month列没有同时等于1,又等于2的数据行
nrow(hf2)
	[1] 0
## 例子2:满足数据框hflights中Month列等于1且DayofMonth列等于2
hf3 = filter(hflights, Month == 1 & DayofMonth == 2)
## 在filter中,','直接相当于'&'
## 为了统一,这种方法也不推荐使用
hf3 = filter(hflights, Month == 1, DayofMonth == 2)
nrow(hf3)
	[1] 678

两个以上的条件:至少满足其中一个(相当于逻辑“或”)。

# 这里以两个条件为例
## 例子1:满足数据框hflights中Month列同时等于1或2
hf4 = filter(hflights, Month == 1 | Month == 2)
## 其值等于18910(Month = 1) + 17128(Month = 1)
nrow(hf4)
	[1] 36038
## 例子2:满足数据框hflights中Month列等于1或DayofMonth列等于2
hf5 = filter(hflights, Month == 1 | DayofMonth == 2)
nrow(hf5)
	[1] 25764

数据选择

数据选择是选择数据框中的制定的列,这里使用的数据是dplyr包中自带的iris函数。

head(iris)
	  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
	1          5.1         3.5          1.4         0.2  setosa
	2          4.9         3.0          1.4         0.2  setosa
	3          4.7         3.2          1.3         0.2  setosa
	4          4.6         3.1          1.5         0.2  setosa
	5          5.0         3.6          1.4         0.2  setosa
	6          5.4         3.9          1.7         0.4  setosa
  • 直接选取

利用字符向量选取指定列;

iris.part1 = iris[,c('Sepal.Length', 'Sepal.Width')]
head(iris.part1)
	  Sepal.Length Sepal.Width
	1          5.1         3.5
	2          4.9         3.0
	3          4.7         3.2
	4          4.6         3.1
	5          5.0         3.6
	6          5.4         3.9

利用数字向量选择指定列;

# 利用":"选取相邻列
iris.part2 = iris[,1:2]
head(iris.part2)
	  Sepal.Length Sepal.Width
	1          5.1         3.5
	2          4.9         3.0
	3          4.7         3.2
	4          4.6         3.1
	5          5.0         3.6
	6          5.4         3.9
# 利用一般数字向量选取相邻列
iris.part3 = iris[,c(1, 3, 4)]
head(iris.part3)
	  Sepal.Length Petal.Length Petal.Width
	1          5.1          1.4         0.2
	2          4.9          1.4         0.2
	3          4.7          1.3         0.2
	4          4.6          1.5         0.2
	5          5.0          1.4         0.2
	6          5.4          1.7         0.4

利用“-”结合数字向量排除数据框的某些列。

iris.part4 = iris[,-(1:2)]
head(iris.part4)
	  Petal.Length Petal.Width Species
	1          1.4         0.2  setosa
	2          1.4         0.2  setosa
	3          1.3         0.2  setosa
	4          1.5         0.2  setosa
	5          1.4         0.2  setosa
	6          1.7         0.4  setosa
iris.part5 = iris[,-c(1, 3, 4)]
head(iris.part5)
	  Sepal.Width Species
	1         3.5  setosa
	2         3.0  setosa
	3         3.2  setosa
	4         3.1  setosa
	5         3.6  setosa
	6         3.9  setosa
  • 利用dplyr包中的select函数

select函数能完成上部分基础函数的所有操作。plyr包中也没有相似功能的select函数。

# 利用列名选取指定列
iris.part1 = select(iris, Sepal.Length, Sepal.Width)
# 甚至可以对选取的列进行重命名
iris.part1 = select(iris, Sepal_length = Sepal.Length, Sepal_Width = Sepal.Width)
head(iris.part1)
	  Sepal_length Sepal_Width
	1          5.1         3.5
	2          4.9         3.0
	3          4.7         3.2
	4          4.6         3.1
	5          5.0         3.6
	6          5.4         3.9
# 利用数字向量选择指定列
iris.part2 = select(iris,1:2)
iris.part3 = iris[, c(1, 3, 4)]
# * 利用"-"结合数字向量排除数据框的某些列 
iris.part4 = select(iris,-c(1:2))
iris.part5 = select(iris,-c(1, 3, 4))

select函数还有自己的特点:

  • ”:”支持相邻列名的选取
iris.part6 = select(iris,Sepal.Length:Petal.Length)
head(iris.part6)
	  Sepal.Length Sepal.Width Petal.Length
	1          5.1         3.5          1.4
	2          4.9         3.0          1.4
	3          4.7         3.2          1.3
	4          4.6         3.1          1.5
	5          5.0         3.6          1.4
	6          5.4         3.9          1.7
  • 支持某些特定语法格式
# 以"Petal"开始的列
head(select(iris, starts_with("Petal")))
	  Petal.Length Petal.Width
	1          1.4         0.2
	2          1.4         0.2
	3          1.3         0.2
	4          1.5         0.2
	5          1.4         0.2
	6          1.7         0.4
# 以"Width"结尾的列
head(select(iris, ends_with("Width")))
	  Sepal.Width Petal.Width
	1         3.5         0.2
	2         3.0         0.2
	3         3.2         0.2
	4         3.1         0.2
	5         3.6         0.2
	6         3.9         0.4
# 包含"etal"的列
head(select(iris, contains("etal")))
	  Petal.Length Petal.Width
	1          1.4         0.2
	2          1.4         0.2
	3          1.3         0.2
	4          1.5         0.2
	5          1.4         0.2
	6          1.7         0.4
# 甚至可以对上述个操作用"-"
select(iris, -starts_with("Petal"))
select(iris, -ends_with("Width"))
select(iris, -contains("etal"))
select(iris, -Petal.Length, -Petal.Width)
  • “-”去除指定列
iris.part7 = select(iris,-(Sepal.Length:Petal.Length))
head(iris.part7)
	  Petal.Width Species
	1         0.2  setosa
	2         0.2  setosa
	3         0.2  setosa
	4         0.2  setosa
	5         0.2  setosa
	6         0.4  setosa

这里,主要讲述的是结合“:”的使用方法。其实正如上个例子那样,”-“也可与特定的语法格式结合使用。

对所有列进行相同操作

这里的操作主要指求和、平均值、方差、标准、最小值、最大值以及简单的四则运算。

  • colSums和colMeans 基础包里的colSums和colMeans函数,只能对所有列进行求和和求平均值操作,并且要求所有数据列必须是数字型的, 否则会提示错误。
library(hflights)
head(hflights)

# 提取数字类型列
hflights.dat = hflights[,! colnames(hflights) %in% c('CancellationCode', 'UniqueCarrier', 'TailNum', 'Origin', 'Dest')]
head(hflights.dat)
summary(hflights.dat)
colSums(hflights.dat, na.rm = T)
colMeans(hflights.dat, na.rm = T)
  • dplyr包的summarise_all()或者mutate_all()函数

summarise_all()或者mutate_all()函数可以进行求平均值、标准差、方差、最小值和最大值,此时被处理的数据列也不需要必须是数字类型(只是此时会有警告提示)。然而,无论如何要进行求和操作时,所有数据列必须是数字类型(原因是sum函数对字符求和,直接返回错误,而求平均值、标准差和方差只是返回NA,并提示警告,最小值和最大值时返回真实的结果)。

  • summarise_all()函数
# 平均值,字符平均值返回NA
summarise_all(hflights, mean)
# 标准差,字符标准差返回NA
summarise_all(hflights, sd)
# 方差,字符方差返回NA
summarise_all(hflights, var)
# 最小值,字符最小值也是可以运算的
summarise_all(hflights, min)
# 最大值,字符最大值也是可以运算的
summarise_all(hflights, max)

# 求和
hflights.dat = hflights[,! colnames(hflights) %in% c('CancellationCode', 'UniqueCarrier', 'TailNum', 'Origin', 'Dest')]
summarise_all(hflights.dat, sum))

  • mutate_all()函数

区别于summarise_all()函数在于mutate_all()函数产生与原数据相同行和列数的结果,这里mutate_all以及下面的mutate_at()和mutate_if()函数也不同于dplyr包的mutate()函数,mutate函数在原始数据后面产生新的结果,而mutate_系列函数则直接产生与原数据相同行和列数的结果。

temp = mutate_all(hflights.dat,  mean))
head(hflights)
head(temp)

此外,summarise_all()和mutate_all()函数中使用的函数还可以使用完全形式,这时候不仅可以更改结果列的名字。mutate_all()的结果将与mutate函数一样在原始数据后面产生新的结果。

mutate_all(hflights, funs("in" = . / 2.54))
mutate_all(hflights,funs(med = median))
summarise_all(hflights,funs(med = median))
# 平均值、最小值和最大值
summarise_all(hflights, funs(mean, min, max))

  • plyr包的colwise函数

plyr包的colwise函数也能对数据框的所有列进行相同的操作。同样可以直接进行求平均值、标准差、方差、最小值和最大值,此时被处理的数据列也不需要必须是数字类型(只是此时会有警告提示)。当所有数据列都是数字类型可以直接求和。当然也可以多个指标同时计算。

# 平均值,字符平均值返回NA
colwise(mean)(hflights)
# 标准差,字符标准差返回NA
colwise(sd)(hflights)
# 方差,字符方差返回NA
colwise(var)(hflights)
# 最小值,字符最小值也是可以运算的
colwise(min)(hflights)
# 最大值,字符最大值也是可以运算的
colwise(max)(hflights)
# 平均值、最小值和最大值
colwise(mean, min, max)(hflights)

# 求和
hflights.dat = hflights[,! colnames(hflights) %in% c('CancellationCode', 'UniqueCarrier', 'TailNum', 'Origin', 'Dest')]
colwise(sum)(hflights)

# 若果某一列中有NA,要想得到结果可以通过调整函数内部的na.rm参数来实现
# 平均值
colwise(function(x)mean(x, na.rm = T))(hflights)
# 标准差
colwise(function(x)sd(x, na.rm = T))(hflights)
# 方差
colwise(function(x)var(x, na.rm = T))(hflights)
# 最小值
colwise(function(x)min(x, na.rm = T))(hflights)
# 最大值
colwise(function(x)max(x, na.rm = T))(hflights)
# 求和
colwise(function(x)sum(x, na.rm = T))(hflights.dat)

temp3 = colwise(function(x){x + 1})(hflights.dat)
head(hflights)
head(temp3)
# 事实上四则运算根本不需要借助函数来实现
temp2 = hflights.dat + 1
Previous     Next Xu Kuang /
Published under (CC) BY-NC-SA in categories 技术篇  tagged with R  dplyr