R語言數據集常用操作彙總

在做數據挖掘時,拿來的數據集一般不能直接用,要進行一些操作比如總覽、重命名、合併、刪除等等,現在本人把這些操作總結出來,以備後用。
下面我們以一個美國出租車的數據集taxi.csv(以下簡稱dataset)爲例進行總結,由於數據量太大,我們只拿前10000個數據說事,數據集可以免費下載。

dataset <- read.csv("taxi.csv", header = TRUE)[1:10000, ]
一、總覽數據

拿到數據集後,我們要先看下數據集是什麼樣的,有多少行、多少列,某列表式的意義是什麼,數據類型是什麼,有哪幾種數據等等。

1、class()函數

這個函數很常用,就是返回一個變量的數據類型——數據框、列表、向量等等。

> class(dataset)
[1] "data.frame"

噢,dataset這個東西是個數據框。

> class(dataset[, 1])
[1] "integer"

噢,dataset第一列的數據是整型。


2、dim()函數

dim()函數用於查看數據的維度。

> dim(dataset)
[1] 10000    19

結果表示我們的數據集有10000行,也就是10000個樣本,19列,也就是19個屬性變量。


3、colnames() / names()函數

那都有哪些屬性變量呢,我們使用colnames() / names()看一下。

> colnames(dataset)
 [1] "VendorID"              "tpep_pickup_datetime"  "tpep_dropoff_datetime"
 [4] "passenger_count"       "trip_distance"         "pickup_longitude"     
 [7] "pickup_latitude"       "RatecodeID"            "store_and_fwd_flag"   
[10] "dropoff_longitude"     "dropoff_latitude"      "payment_type"         
[13] "fare_amount"           "extra"                 "mta_tax"              
[16] "tip_amount"            "tolls_amount"          "improvement_surcharge"
[19] "total_amount"    

names()函數同樣返回這些信息,這些屬性的意義我在這就不多說了,數據集有官方解釋文檔,如下:
在這裏插入圖片描述


4、str()函數

這個函數返回的信息非常詳細,它返回了1、2、3這四個函數的所有結果:數據類型、維度、列名、每列數據類型等等!不過就是看起來有點眼暈。

> str(dataset)
'data.frame':	10000 obs. of  19 variables:
 $ VendorID             : int  2 2 2 2 2 2 2 2 1 1 ...
 $ tpep_pickup_datetime : Factor w/ 551383 levels "2016-01-08T00:00:00Z",..: 70772 72121 73789 74512 81934 82714 83440 86916 1 2 ...
 $ tpep_dropoff_datetime: Factor w/ 553414 levels "2016-01-08T00:01:23Z",..: 71245 73004 73945 74873 81922 82804 84634 86999 490 261 ...
 $ passenger_count      : int  2 1 1 1 1 1 1 1 1 1 ...
 $ trip_distance        : num  1.83 3.18 1.17 5.27 1.14 1.7 5.26 1.04 5.2 2.2 ...
 $ pickup_longitude     : num  -74 -74 -74 -74 -74 ...
 $ pickup_latitude      : num  40.7 40.7 40.8 40.8 40.8 ...
 $ RatecodeID           : int  1 1 1 1 1 1 1 1 1 1 ...
 $ store_and_fwd_flag   : Factor w/ 2 levels "N","Y": 1 1 1 1 1 1 1 1 1 1 ...
 $ dropoff_longitude    : num  -74 -74 -74 -74 -74 ...
 $ dropoff_latitude     : num  40.7 40.8 40.8 40.8 40.7 ...
 $ payment_type         : int  1 1 2 1 2 1 1 1 1 2 ...
 $ fare_amount          : num  10 14.5 7 16.5 6 7.5 21 6.5 18 9.5 ...
 $ extra                : num  0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0 0.5 ...
 $ mta_tax              : num  0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 ...
 $ tip_amount           : num  1.5 3.16 0 2 0 1.76 3 1 2 0 ...
 $ tolls_amount         : num  0 0 0 0 0 0 0 0 0 0 ...
 $ improvement_surcharge: num  0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 ...
 $ total_amount         : num  12.8 19 8.3 19.8 7.3 ...

5、根據列名獲取某一列數據

“$” 這個符號用於取出數據集的某一列全部數據,它返回一個向量,"$"後面一半跟數據集某一列的列名。

> dataset$total_amount
[1]  12.80  18.96   8.30  19.80   7.30  10.56  25.30   8.80  20.80  10.80   6.80
  [12]  11.80   8.80  30.30   7.30  19.80   7.55   6.30   7.30  35.15   9.96  22.80
  [23]   9.95   6.80  24.10   9.80  18.50   5.84  73.34  34.80  17.16  11.75  25.30
  [34]  20.75   9.30  39.30   9.95  11.16  24.30  11.30   9.80   7.80  25.13   8.30
[ reached getOption("max.print") -- omitted 9956 entries ]

我們得到了dataset中total_amount這一列的數據,空間有限,只給我們顯示了前44個數據。

> class(dataset$total_amount)
[1] "numeric"

這一列是數值型的。


當然也可以直接用“列名+方括號”訪問:

dataset[c("passenger_count", "trip_distance")]
    passenger_count trip_distance
1                 2          1.83
2                 1          3.18
3                 1          1.17
4                 1          5.27
5                 1          1.14
6                 1          1.70
7                 1          5.26
 [ reached 'max' / getOption("max.print") -- omitted 9993 rows ]

取出passenger_count和trip_distance這兩列。


6、獲取某一行或多行數據

我們知道數據集每一行並沒有“行名”,因此我們只能使用下標索引的方式獲取行數據,這一點與高級語言C++、Java或Python很像。我們把數據集想象成一個二維矩陣,有m行n列,只不過傳統二維矩陣沒有列名,而data frame有列名罷了。數據集的下標索引標準爲data[m, n],m、n可以是一個數字,表示第幾行、第幾列,也可以是一個向量,表示哪幾行、哪幾列,只寫m不寫n表示取出m行所有列,反之亦同。注意,R語言中下標是從1開始的。

# 取出第一行(所有列)
> dataset[1, ]
  VendorID tpep_pickup_datetime tpep_dropoff_datetime passenger_count trip_distance
1        2 2016-01-08T21:29:06Z  2016-01-08T21:42:15Z               2          1.83
  pickup_longitude pickup_latitude RatecodeID store_and_fwd_flag dropoff_longitude
1        -74.00793        40.74529          1                  N         -73.98163
  dropoff_latitude payment_type fare_amount extra mta_tax tip_amount tolls_amount
1          40.7405            1          10   0.5     0.5        1.5            0
  improvement_surcharge total_amount
1                   0.3         12.8

注意,data frame的每一列仍是一個data frame,只不過它只有1行罷了。

# 取出第一列(所有行)
> dataset[, 3]
   [1] 2016-01-08T21:42:15Z 2016-01-08T22:11:39Z 2016-01-08T22:27:23Z
   [4] 2016-01-08T22:42:51Z 2016-01-09T00:40:30Z 2016-01-09T00:55:14Z
   [7] 2016-01-09T01:25:55Z 2016-01-09T02:05:33Z 2016-01-08T00:14:11Z
  [10] 2016-01-08T00:09:56Z 2016-01-08T00:03:09Z 2016-01-08T00:07:51Z
  [13] 2016-01-08T00:08:55Z 2016-01-08T00:23:34Z 2016-01-08T00:06:39Z
  [16] 2016-01-08T00:18:08Z 2016-01-08T00:04:23Z 2016-01-08T00:03:16Z
  [19] 2016-01-08T00:06:28Z 2016-01-08T00:34:00Z 2016-01-08T00:06:06Z
[ reached getOption("max.print") -- omitted 9979 entries ]

一列數據構成一個向量,而不是data frame。

# 取出第3行第5列的數據
> dataset[3, 5]
[1] 1.17

單個值。

# 取第1~5行,第4列的數據
# 或簡寫爲 dataset[1:5, 4]
> dataset[c(1:5), 4]
[1] 2 1 1 1 1

它是一個整型向量。

# 取第2、4、5行,第3、4列的數據
```python
> dataset[c(2, 4, 5), c(3, 4)]
 tpep_dropoff_datetime passenger_count
2  2016-01-08T22:11:39Z               1
4  2016-01-08T22:42:51Z               1
5  2016-01-09T00:40:30Z               1

它是一個data frame。


# 從第4行開始一律不要
> subset <- dataset[, -c(4:nrow(dataset))]
> dim(subset)
[1] 10000     3

剩下的數據集保留了全部行,但是隻有前三列。


7、table()函數

通俗講,這個函數可以自動爲你完成數據集某列每個元素的頻度統計,官方文檔是這麼說的:

> ?table()
Cross Tabulation and Table Creation

Description

table uses the cross-classifying factors to build a contingency table of the counts at each combination of factor levels.

有道翻譯:“table” 使用交叉分類因子來構建每個因子級別組合的計數的列聯表。

我們看下效果:

> table(dataset$passenger_count)

   1    2    3    4    5    6 
8109 1381  331  168    6    5 

table是針對某一列起作用的,它返回該列出現的每種數據出現的頻數。如上所示,數字1出現了8109次,數據2出現了1381次等等。


二、數據集操作

1、which()函數

這個函數功能很多,我們先講他的篩選功能。

這個函數返回向量中符合條件的元素下標。

> which(dataset$passenger_count != 2)
   [1]    2    3    4    5    6    7    8    9   10   11   12   13   14   16   17   18
  [17]   20   21   22   23   24   25   26   28   29   30   31   32   33   34   35   38
  [33]   39   40   41   42   46   47   48   49   51   52   53   55   56   57   58   60
  [49]   61   63   64   65   67   69   71   72   73   75   76   77   79   80   81   82
  [65]   83   85   86   87   88   90   91   92   93   95   96   97   98   99  100  101

可以看到,返回的結果均爲passenger_count這一列的元素不等於2的下標,那有了這些下標我們就可以取出我們想要的數據。

> subset <- dataset[-which(dataset$passenger_count == 3), ]
> table(subset$passenger_count)

   1    2    4    5    6 
8109 1381  168    6    5 

我們篩選出把passenger_count爲3的所有數據(行)去掉後剩餘的數據集,再使用table(),發現passenger_count中已經沒有爲3的數據了。


2、列重命名

我們可以使用colnames(dataframe)來獲取數據框的列名,根據這個我們可以對某列重命名。

> colnames(dataset)[5] <- "rename"
> colnames(dataset)
 [1] "VendorID"              "tpep_pickup_datetime"  "tpep_dropoff_datetime"
 [4] "passenger_count"       "rename"                "pickup_longitude"     
 [7] "pickup_latitude"       "RatecodeID"            "store_and_fwd_flag"   
[10] "dropoff_longitude"     "dropoff_latitude"      "payment_type"         
[13] "fare_amount"           "extra"                 "mta_tax"              
[16] "tip_amount"            "tolls_amount"          "improvement_surcharge"
[19] "total_amount"   

我們把第5列重命名爲“rename”。


3、增刪列

我們可以直接用“數據集$新列名”的方式添加一列。

> newcolumn <- rep(1:10000)
> dataset$added_col <- newcolumn
> colnames(dataset)
 [1] "VendorID"              "tpep_pickup_datetime"  "tpep_dropoff_datetime"
 [4] "passenger_count"       "rename"                "pickup_longitude"     
 [7] "pickup_latitude"       "RatecodeID"            "store_and_fwd_flag"   
[10] "dropoff_longitude"     "dropoff_latitude"      "payment_type"         
[13] "fare_amount"           "extra"                 "mta_tax"              
[16] "tip_amount"            "tolls_amount"          "improvement_surcharge"
[19] "total_amount"          "added_col"  

我們添加了added_col這一列,它是1~10000的整型向量。
也可以使用cbind()函數來按照兩個數據集縱向合併的形式添加列。

> dataset <- cbind(dataset, added_col2 = newcolumn)
> colnames(dataset)
 [1] "VendorID"              "tpep_pickup_datetime"  "tpep_dropoff_datetime"
 [4] "passenger_count"       "rename"                "pickup_longitude"     
 [7] "pickup_latitude"       "RatecodeID"            "store_and_fwd_flag"   
[10] "dropoff_longitude"     "dropoff_latitude"      "payment_type"         
[13] "fare_amount"           "extra"                 "mta_tax"              
[16] "tip_amount"            "tolls_amount"          "improvement_surcharge"
[19] "total_amount"          "added_col"             "added_col2"  

將原有數據集dataset和新的一列newcolumn縱向合併,並重新取名爲added_col2。


刪除列可以使用which函數,根據列名對列進行篩選,然後只要篩選出來的列。

> dataset <- dataset[, -which(colnames(dataset) %in% c("added_col", "added_col2", "added_col3", "added_col4"))]
> colnames(dataset)
 [1] "VendorID"              "tpep_pickup_datetime"  "tpep_dropoff_datetime"
 [4] "passenger_count"       "rename"                "pickup_longitude"     
 [7] "pickup_latitude"       "RatecodeID"            "store_and_fwd_flag"   
[10] "dropoff_longitude"     "dropoff_latitude"      "payment_type"         
[13] "fare_amount"           "extra"                 "mta_tax"              
[16] "tip_amount"            "tolls_amount"          "improvement_surcharge"
[19] "total_amount"    

我們又把之前新增的幾列刪除了。


當然也可以直接以下標的形式刪除列。

> dim(dataset)
[1] 10000    19
> dataset <- dataset[, -5]
> dim(dataset)
[1] 10000    18

我們刪除了第5列。


4、增刪行

與增刪列不同,我們無法根據“行名”來選擇行,因此可以使用rbind()來以行爲單位橫向合併兩個數據集的形式增加行。

> newrows <- dataset[4:6, ]
> dataset <- rbind(dataset, newrows)
> dim(dataset)
[1] 10003    18

我們把dataset的第4~6這3行與原數據集橫向合併,實現了行的增加。


行的刪除就通過下標的形式進行操作。

> dataset <- dataset[-2:4, ]
> dim(dataset)
[1] 10000    18

我們刪除了第2~4這3行。


5、數據類型轉換

有些數據集導入之後,對於某一列可能不是我們需要的數據類型,因此需要轉換。一般的用法是"as.需要的數據類型(列名)"。

我們先看下每列的數據類型

> dataset %>% sapply(class)
             VendorID  tpep_pickup_datetime tpep_dropoff_datetime       passenger_count 
            "integer"              "factor"              "factor"             "integer" 
     pickup_longitude       pickup_latitude            RatecodeID    store_and_fwd_flag 
            "numeric"             "numeric"             "integer"              "factor" 
    dropoff_longitude      dropoff_latitude          payment_type           fare_amount 
            "numeric"             "numeric"             "integer"             "numeric" 
                extra               mta_tax            tip_amount          tolls_amount 
            "numeric"             "numeric"             "numeric"             "numeric" 
improvement_surcharge          total_amount 
            "numeric"             "numeric" 

發現passenger_count這列是integer類型,我們想把它改爲因子類型(假設,事實上不需要改)。

> dataset$passenger_count <- factor(dataset$passenger_count, level = c("1", "2", "3", "4", "5", "6"))

> str(dataset$passenger_count)
 Factor w/ 6 levels "1","2","3","4",..: 2 1 1 1 1 1 1 1 1 1 ...

三、高級

1、with()範圍限定

with()函數可以限定操作只在某個數據集的範圍內起作用,比如我們想計算passenger_count和trip_distance這兩列的和,我們可以:

> head(dataset$passenger_count + dataset$trip_distance, 10)
[1] 3.83 4.18 2.17 6.27 2.14 2.70 6.26 2.04 6.20 3.20

但是每次都要輸入數據集名稱和$符號,很麻煩,可以使用with,使操作限定在dataset數據集內:

> with(dataset, head(passenger_count + trip_distance, 10))
 [1] 3.83 4.18 2.17 6.27 2.14 2.70 6.26 2.04 6.20 3.20

就方便了很多。


2、缺失值(NA)處理

很多時候我們的數據集有很多沒有記錄的觀測點,也就是所謂的缺失值,在R中會顯示爲NA,那有時候我們想去掉帶有NA的一行記錄怎麼辦呢?

在這裏插入圖片描述

假設我們的數據集叫做data,但凡是出現NA的行我們都想把它刪除,可以使用以下語句。

# 首先獲取出現過NA的行號下標
NA.index = which(rowSums(is.na(data)) > 0)

# 然後從數據集data中刪除或這些下標的行號
new_data <- data[-NA.index, ]

在這裏插入圖片描述


這樣,就消除了全部帶有缺失值的觀測行,觀測值少了當然樣本容量也會減小。那有時候我們擬合模型的時候需要大量的樣本來控制過擬合,這時候該怎麼辦呢?我們只需要保證訓練集中的response variable也就是ytrain裏沒有缺失值就好了,而xtrain有沒有缺失值我們不關心(有的算法允許帶有缺失值),那這個時候只需要把ytrain這一列數據中的NA刪掉就好(當然對應xtrain的一行也要刪除)。

> length(which(is.na(ytrain) == TRUE))
[1] 358

ytrain中有358個缺失值。

# 獲取缺失值下標
> NA.index = which(is.na(ytrain) == TRUE)

# 看看是否獲取成功
> length(which(is.na(ytrain[-NA.index]) == TRUE))
[1] 0

# 從ytrain / xtrain中刪除相應觀測值 / 行
new_ytrain <- ytrain[-NA.index]
new_xtrain <- xtrain[-NA.index, ]

這樣,new_ytrain中已經沒有了缺失值,而new_xtrain中可能還會有缺失值。

當我們的數據只有一維,也就是vector形式的時候,可以使用以下語句獲取含有缺失值的下標:

> NA.index = which(is.na(vector) == TRUE)

當我們的數據有多維,也就是dataframe或matrix形式的時候,可以使用以下語句獲取含有缺失值的下標:

> which(rowSums(is.na(data)) > 0)

3、使用正則表達式grep()

學過linux的同學應該都知道,正則表達式在shell命令行中經常用到,其語法靈活易懂,那麼在R語言中我們同樣可以使用正則表達式來獲取我們想獲得的信息。具體的正則表達式語法可以參考菜鳥教程:
菜鳥教程——正則表達式

grep()可以返回滿足表達式的結果,一般是下標形式。比如我們可以借用grep()來根據列名定位數據集中某列的位置。

# 獲取名爲“q9”、“q13”的列所在位置
COL.index = NA
num = 1
for(i in c("^q9$", "^q13$"))
{
	COL.index[num] = grep(i, colnames(data))
	num = num + 1
}
> COL.index
[1] 4 8

可以看到,“q9”、“q13”的列分別爲於4、8的位置。
當然,要獲取列所在位置比這簡單的方法很多,前面刪除列那一部分就已經講過,這裏只是舉個例子。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章