2017年4月26日 星期三

R | Data manipulation (1): select, filter, slice, piping

這邊要介紹幾個處理資料的幾個功能,因為太長所以分成兩篇,這篇介紹的功能有:select, filter, slice, piping

下篇會介紹:arrange, mutate, summarise

詳細功能介紹請參考這兩頁:Working with Data - Part 1 & Intro to R - Part 3

練習的部分可以參考 slides: Working with Data - Part 1 (pdf)

這幾個功能在 dplyr 這個 package 裡面,所以要先跑。同時要用內建檔案 mtcars 來練習,所以也要叫出來。下面還會用檔案資料 flights,因為它在 nycflights13 這個 packages 裡面,所以也需要安裝。

library(dplyr)
library(nycflights13)
mtcars

先介紹定義功能,幾個 operators 可看這篇

下面先指定 a = 6,然後問 a 是否為 7。

a <- 6
a == 7

[1] FALSE

a 不是 7,所以顯示出來為 FALSE。

如果問:a 不是 7 呢?

a!= 7

[1] TRUE

a 是六不是七是對的,所以顯示為 TRUE。


1. Select function: view only some variables

這是只選某些 variables 出來看,語法是:select(dataframe, var)

只選 mpg 和 wt 這兩項出來看。

select(mtcars, mpg, wt)

                     mpg    wt
Mazda RX4           21.0 2.620
Mazda RX4 Wag       21.0 2.875
Datsun 710          22.8 2.320
Hornet 4 Drive      21.4 3.215
Hornet Sportabout   18.7 3.44
Valiant             18.1 3.460
Duster 360          14.3 3.570
Merc 240D           24.4 3.190
Merc 230            22.8 3.150
Merc 280            19.2 3.440
Merc 280C           17.8 3.440
......

選出 variables 開頭是 "d" 的。

select(mtcars, starts_with("d"))

                     disp drat
Mazda RX4           160.0 3.90
Mazda RX4 Wag       160.0 3.90
Datsun 710          108.0 3.85
Hornet 4 Drive      258.0 3.08
Hornet Sportabout   360.0 3.15
Valiant             225.0 2.76
Duster 360          360.0 3.21
......

列出所有的 variables。

select(mtcars, everything())


2. Filter function: choose observations by their values

和 select() 不同的是 filter() 挑的更進一步,是選出某個 variable 裡的某個觀察(observations),例如下面是選出 cyl 這個 variable 裡面,數值為 8 的那些。

filter(mtcars, cyl == 8)

    mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
2  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
3  16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
4  17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
5  15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
6  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
......

找出小於八的。

filter(mtcars, cyl < 8)

加兩個條件,用「或」(or),指令符號是:

例如下面是找出 cyl 是 4 或 8 的。

filter(mtcars, cyl == 4 | cyl == 8)

    mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
2  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
3  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
4  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
5  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
6  16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
......

在上面的例子中,因為我們想找的是在 cyl 中符合 4 和 8 的條件的,因此我們也可以用 %in% 的語法:var %in% c(obs1, obs2)

這是指在某個 variable 中找出裡面符合觀察值(obs)為特定值的項目,不一定要兩個,可以只有一個,也可以兩個以上,看你想找什麼,用上面的例子就會是:cyl %in% c(4, 8)

filter(mtcars, cyl %in% c(4, 8))

找出同時符合兩個條件的,用「和」(and),指令符號是:

例如下面是找出 cyl 和 carb 都是八的。

filter(mtcars, cyl == 8 & carb == 8)

  mpg cyl disp  hp drat   wt qsec vs am gear carb
1  15   8  301 335 3.54 3.57 14.6  0  1    5    8

用上面的語法前面只會出現數字,如果要顯示出是每列的名稱(也就是哪種車),可以用下面的語法。

mtcars[mtcars$cyl == 4 | mtcars$carb == 8, ]

              mpg cyl disp  hp drat   wt qsec vs am gear carb
Maserati Bora  15   8  301 335 3.54 3.57 14.6  0  1    5    8

select() 是挑出你想看的 variables,那如果想看某種特定條件下 variables 裡面的觀察值呢?例如我想看 variable qsec,但不想看全部的,只想看 cyl = 8 下的 qsec 值是什麼,這時候可以分開設,先用 filter() 找出 cyl = 8 的,然後再用 select() 看裡面的 qsec。

df <- filter(mtcars, cyl == 8)
select(df, qsec)

    qsec
1  17.02
2  15.84
3  17.40
4  17.60
5  18.00
6  17.98
7  17.82
8  17.42
9  16.87
10 17.30
11 15.41
12 17.05
13 14.50
14 14.60


3. Slice function

和上面 filter() 不同的,slice() 是挑選某幾列(row)出來看,例如前三列或最後一列,而不是挑某種特定條件。

例如你只想要列出第三列的資料,可以這樣:

slice(mtcars, 3L)
slice(mtcars, 3)

上面的兩種語法會出現同樣的結果,如下。

# A tibble: 1 x 11
    mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  22.8     4   108    93  3.85  2.32 18.61     1     1     4     1

Note: slice() and filter() do not carry the row names with the subset of rows(注意:filter  和 slice 這兩個功能都不會在表格的前面顯示列的名稱,只有號碼。)

如果你想要列出第 1, 3, 5 列的資料,可以用 c(1, 3, 5)

slice(mtcars, c(1, 3, 5))

# A tibble: 3 x 11
    mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  21.0     6   160   110  3.90  2.62 16.46     0     1     4     4
2  22.8     4   108    93  3.85  2.32 18.61     1     1     4     1
3  18.7     8   360   175  3.15  3.44 17.02     0     0     3     2

如果你想要顯示最後一行,不用找出一共有幾行,可以用這個語法: n() 

n(): the number of observations in the current group.(表示那組有幾個觀察值就是幾個)

把它設在你想要挑選的列值的話,就會顯示最後一列,因為它的值是所有觀察值。例如 mtcars 總共有 32 個觀察值(就是有 32 列),那 n() 就是 32,於是就會顯示出第 32 列。

slice(mtcars, n())

# A tibble: 1 x 11
    mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  21.4     4   121   109  4.11  2.78  18.6     1     1     4     2

在上面的語法中,slice(mtcars, n()) 其實就是 slice(mtcars, 32),但如果用 n() 的話,就可以套用到所有資料李,不用每次改成最後一列的數字。

也可以用 filter() 的功能顯示最後一列,用的語法是:row_number() == n()

filter(mtcars, row_number() == n())

   mpg cyl disp  hp drat   wt qsec vs am gear carb
1 21.4   4  121 109 4.11 2.78 18.6  1  1    4    2

同理,如果要顯示從某行到最後一行的話,可以這樣:

slice(mtcars, 5:n())

# A tibble: 28 x 11
     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  18.7     8 360.0   175  3.15  3.44 17.02     0     0     3     2
 2  18.1     6 225.0   105  2.76  3.46 20.22     1     0     3     1
 3  14.3     8 360.0   245  3.21  3.57 15.84     0     0     3     4
 4  24.4     4 146.7    62  3.69  3.19 20.00     1     0     4     2
 5  22.8     4 140.8    95  3.92  3.15 22.90     1     0     4     2
 6  19.2     6 167.6   123  3.92  3.44 18.30     1     0     4     4
 7  17.8     6 167.6   123  3.92  3.44 18.90     1     0     4     4
 8  16.4     8 275.8   180  3.07  4.07 17.40     0     0     3     3
 9  17.3     8 275.8   180  3.07  3.73 17.60     0     0     3     3
10  15.2     8 275.8   180  3.07  3.78 18.00     0     0     3     3
# ... with 18 more rows

因為 filter() 和 select() 功能都是不會給列名的,只有給數字,我們可以用 add_rownames() 或是 tibble::rownames_to_column() 的功能。

filter(add_rownames(mtcars), cyl == 8, carb == 3)

# A tibble: 3 x 12
      rowname   mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear
        <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  Merc 450SE  16.4     8 275.8   180  3.07  4.07  17.4     0     0     3
2  Merc 450SL  17.3     8 275.8   180  3.07  3.73  17.6     0     0     3
3 Merc 450SLC  15.2     8 275.8   180  3.07  3.78  18.0     0     0     3

Warning message:
Deprecated, use tibble::rownames_to_column() instead.

filter(tibble::rownames_to_column(mtcars),
       cyl == 8, carb == 3)

      rowname  mpg cyl  disp  hp drat   wt qsec vs am gear carb
1  Merc 450SE 16.4   8 275.8 180 3.07 4.07 17.4  0  0    3    3
2  Merc 450SL 17.3   8 275.8 180 3.07 3.73 17.6  0  0    3    3
3 Merc 450SLC 15.2   8 275.8 180 3.07 3.78 18.0  0  0    3    3

在 slice() 的表格裡加 row name 的話就是這樣:(下面顯示第三到五列)

slice(tibble::rownames_to_column(mtcars), c(3:5))

# A tibble: 3 x 12
            rowname   mpg   cyl  disp    hp  drat    wt  qsec    vs    am
              <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>

1        Datsun 710  22.8     4   108    93  3.85 2.320 18.61     1     1
2    Hornet 4 Drive  21.4     6   258   110  3.08 3.215 19.44     1     0
3 Hornet Sportabout  18.7     8   360   175  3.15 3.440 17.02     0     0


Exercise

Q1. 找出 mtcars 檔案裡面 qsec 和 am 的資料,並把檔案裡第一個 column 的資料(i.e., mpg)指定為 am。

因為是要把 qsec 和 am 這兩個 variables 找出來看,所以用的是 select() 這個功能。

select(mtcars, qsec, am = 1)

在 select() 的功能裡,如果用 var = #  這個語法,就是指把某個 variable 指定為檔案裡某一行的 variable,例如上面的 am = 1 就是指把 am 指定為檔案裡原本為第一行的 mpg,你可以看到 am 裡出現的的數值其實是 mpg 裡的。

                     qsec   am
Mazda RX4           16.46 21.0
Mazda RX4 Wag       17.02 21.0
Datsun 710          18.61 22.8
Hornet 4 Drive      19.44 21.4
Hornet Sportabout   17.02 18.7

下面我們用 am = 2,檔案裡的第二欄是 cyl,所以 am 裡的值會變成 cyl 裡的。

select(mtcars, qsec, am = 2)

                     qsec am
Mazda RX4           16.46  6
Mazda RX4 Wag       17.02  6
Datsun 710          18.61  4
Hornet 4 Drive      19.44  6
Hornet Sportabout   17.02  8

Q2. 找出檔案裡 am 是 1 的。

因為是挑處某個 variable 裡面的某個觀察值,所以要用 filter(),和上面不同的地方是要用 ==。

filter(mtcars, am == 1)

    mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
4  32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
5  30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2

Q3. Extract the 1/4 mile time for cars with manual transmissions (找出檔案裡面 am 是 1 的 qsec 值)

am: transmission (0 = automatic, 1 = manual)
qsec: 1/4 mile time

select(filter(mtcars, am == 1), qsec)

    qsec
1  16.46
2  17.02
3  18.61
4  19.47
5  18.52
6  19.90
7  18.90
8  16.70
9  16.90
10 14.50
11 15.50
12 14.60
13 18.60

Q4. Extract the mpg & wt for those cars with 5 gears or a manual transmission (找出檔案裡面 am 值是 1 或 gear 值是 5 的 qsec 值)

select(filter(mtcars, gear == 5 | am == 1), mpg, wt)

    mpg    wt
1  21.0 2.620
2  21.0 2.875
3  22.8 2.320
4  32.4 2.200
5  30.4 1.615
6  33.9 1.835
7  27.3 1.935
8  26.0 2.140
9  30.4 1.513
10 15.8 3.170
11 19.7 2.770
12 15.0 3.570
13 21.4 2.780


4. Piping (%>%): used when combining several function call together the command can be very hard to read

這個功能在 library(dplyr) 裡面,如果你用的疊層太多,很長的話,可以用 piping 把它分層變短。

Note: f(x) %>% g(y) is the same as g(f(x),y)

Exercise 1: Use %>% for Q3(把上面 Q3 的答案用 %>% 寫出來)

select(filter(mtcars, am == 1), qsec)

上面的是指在 mtcars 裡挑出 am == 1,再從裡面挑出 qsec 的資料。也就是說,mtcars 是最外層的,再來是 am == 1,最後才是 qsec。

mtcars %>%
   filter(am == 1) %>%
   select(qsec)

Exercise 2:

as.data.frame(select(filter(add_rownames(mtcars),
              mpg >= 30), rowname, mpg, cyl, hp))

把上面的語法用 %>% 分句寫。拆開來看是把 mtcars 加了列名之後,挑出 mpg >=30,再從裡面挑出 rowname, mpg cyl, hp 這幾項用 dataframe 的形式呈現出來。

add_rownames(mtcars) %>%
   filter(mpg >= 30) %>%
   select(rowname, mpg, cyl, hp) %>%
   as.data.frame()


最後,我們用檔案資料 flights 來練習一下。

Q1. Select all flights on January 2, but leave out the date columns.

選出所以一月二號的班機,不用顯示出日期(年月日)的那幾欄。

下面先看一下 flights 長怎樣。

head(flights)

# A tibble: 6 x 19
   year month   day dep_time sched_dep_time dep_delay arr_time
  <int> <int> <int>    <int>          <int>     <dbl>    <int>
1  2013     1     1      517            515         2      830
2  2013     1     1      533            529         4      850
3  2013     1     1      542            540         2      923
4  2013     1     1      544            545        -1     1004
5  2013     1     1      554            600        -6      812
6  2013     1     1      554            558        -4      740
# ... with 10 more variables: carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
# distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

挑出 variables 裡面的某個觀察,要用 filter() 挑出 month == 1day == 2。要挑出某些 variables 的話要用 select(),如果要剔除的話同樣用 select(),但是在不要的 variables 前面加  -

flights %>%
  filter(month == 1, day == 2) %>%
  select(-year, -month, -day)

也可以這樣:

flights %>%
  filter(month == 1, day == 2) %>%
  select(-(year:day))

# A tibble: 943 x 16
   dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
      <int>          <int>     <dbl>    <int>          <int>     <dbl>
 1       42           2359        43      518            442        36
 2      126           2250       156      233           2359       154
 3      458            500        -2      703            650        13
 4      512            515        -3      809            819       -10
 5      535            540        -5      831            850       -19

可以看到上面的顯示的結果沒有 year, month 和 day 那三欄。



另外幾個處理檔案資料的功能請看這篇:R | Data manipulation (2): arrange, mutate, summarise









沒有留言:

張貼留言

歡迎發表意見