1. 程式人生 > >盤一盤Tidyverse| 篩行選列之select,玩轉列操作

盤一盤Tidyverse| 篩行選列之select,玩轉列操作

原文連結:https://mp.weixin.qq.com/s/ldO0rm3UM_rqlFnU3euYaA

2020年,開封 《R 資料科學》R for data science,系統學習R 資料處理。

 

在一個典型的資料科學專案中,需要的工具模型大體如下圖所示。 ---R for Data Science

資料匯入和資料整理較乏味和無聊,很容易從入門到放棄!從資料轉換和視覺化開始,容易看到成果,保持學習的動力。

之前的推文講了一些生信常見圖形的繪製(後續會一直補充),現在開始主要依據《R資料科學》一書逐漸介紹資料分析的過程。

本次根據 msleep資料集,盤一盤“列”的操作。

 

一 載入資料和R包

#載入R包
#install.packages("tidyverse")
library("tidyverse")
#檢視內建資料集
head(msleep,2)
# A tibble: 6 x 11
 name  genus vore  order conservation sleep_total sleep_rem sleep_cycle awake
 <chr> <chr> <chr> <chr> <chr>              <dbl>     <dbl>       <dbl> <dbl>
1 Chee~ Acin~ carni Carn~ lc                  12.1      NA        NA      11.9
2 Owl ~ Aotus omni  Prim~ NA                  17         1.8      NA       7  
# ... with 2 more variables: brainwt <dbl>, bodywt <dbl>

上述資料集有11列(變數),而生信中的臨床資訊,實驗室檢驗指標經常上百,基因(突變,表達)資訊更是成千上萬。此時可以基於變數名,使用select() 函式快速生成一個有用的變數子集。

 

二 以列之名

2.1 選擇對應名稱列

使用select()直接選擇列名稱所對應的列。

#選擇name, sleep_total ,awake三列,使awake在中間
msleep %>%
 select(name, awake, sleep_total) %>% head()

1579413836903 彩蛋:新增順序即為輸出順序。

 

2.2 選擇若干連序列

使用start_col:end_col

語法選擇若干的連續列。

msleep %>%
 select(name:vore, sleep_total:awake) %>% head(2)
# A tibble: 6 x 7
 name                       genus      vore  sleep_total sleep_rem sleep_cycle awake
 <chr>                      <chr>      <chr>       <dbl>     <dbl>       <dbl> <dbl>
1 Cheetah                    Acinonyx   carni        12.1      NA        NA      11.9
2 Owl monkey                 Aotus      omni         17         1.8      NA       7  

與基本語法類似,用來選擇連續的列。

2.3 根據部分列名稱選擇列

如果列名結構相似,可使用starts_with()ends_with()contains()完成部分匹配。

1)starts_with()選擇以“XX”開頭的所有列

msleep %>%
 select(name, starts_with("sleep")) %>% head(2)
# A tibble: 2 x 4
 name       sleep_total sleep_rem sleep_cycle
 <chr>            <dbl>     <dbl>       <dbl>
1 Cheetah           12.1      NA            NA
2 Owl monkey        17         1.8          NA

2)ends_with()選擇以“XX”結尾的所有列

msleep %>%
 select(ends_with("e")) %>% head(2)
# A tibble: 2 x 4
 name       vore  sleep_cycle awake
 <chr>      <chr>       <dbl> <dbl>
1 Cheetah    carni          NA  11.9
2 Owl monkey omni           NA   7

3) contains()選擇包含“XX”的所有列

msleep %>%
 select(contains("leep")) %>% head(2)
# A tibble: 2 x 3
 sleep_total sleep_rem sleep_cycle
       <dbl>     <dbl>       <dbl>
1        12.1      NA            NA
2        17         1.8          NA

4)matches() 選擇基於正則的列

如果列名模式不相似,使用matches()選擇對應正則表示式的列。

#選擇任何包含“a”,後跟一個或多個其他字母和“e”的列
msleep %>%
 select(matches("a.+e")) %>% head(2)
# A tibble: 2 x 2
 name       awake
 <chr>      <dbl>
1 Cheetah     11.9
2 Owl monkey   7  

 

三 邏輯之名

3.1 基於資料型別選擇列

使用select_if()選擇所有數值列select_if(is.numeric),此外還可用is.numericis.integeris.doubleis.logicalis.factor

msleep %>%
 select_if(is.numeric) %>% head(2)
# A tibble: 2 x 6
 sleep_total sleep_rem sleep_cycle awake brainwt bodywt
       <dbl>     <dbl>       <dbl> <dbl>   <dbl>  <dbl>
1        12.1      NA            NA  11.9 NA       50  
2        17         1.8          NA   7    0.0155   0.48

3.2 基於邏輯表示式選擇列

msleep %>%
 select_if(is.numeric) %>%
 select_if(~mean(., na.rm=TRUE) > 10) %>% head(2)
# A tibble: 2 x 3
 sleep_total awake bodywt
       <dbl> <dbl>  <dbl>
1        12.1  11.9  50  
2        17     7     0.48

注:select_all / if 函式要求將函式作為引數傳遞。因為mean > 10 本身不是函式,所以需要前面新增“~”表示匿名函式;或者使用funs()先將函式包裝。

more_than_10 <- function(x) {
 mean(x,na.rm=TRUE) > 10
}
msleep %>% select_if(is.numeric) %>% select_if(more_than_10) %>% head(2)
# A tibble: 2 x 3
 sleep_total awake bodywt
       <dbl> <dbl>  <dbl>
1        12.1  11.9  50  
2        17     7     0.48

結果同上。

msleep %>%
 select_if(~is.numeric(.) & mean(., na.rm=TRUE) > 10) %>% head(2)

結果同上!

 

3.3 選擇唯一值數目符合條件的列

結合 n_distinct()選擇具有不少於20個不同答案的列。

msleep %>%
 select_if(~n_distinct(.) >= 20) %>% head(2)
# A tibble: 2 x 8
 name       genus    sleep_total sleep_rem sleep_cycle awake brainwt bodywt
 <chr>      <chr>          <dbl>     <dbl>       <dbl> <dbl>   <dbl>  <dbl>
1 Cheetah    Acinonyx        12.1      NA            NA  11.9 NA       50  
2 Owl monkey Aotus           17         1.8          NA   7    0.0155   0.48

 

四 調整列順序

4.1 選擇列名稱時候直接調整

#選擇name, sleep_total ,awake三列,使awake在中間
msleep %>%
 select(name, awake, sleep_total) %>% head(2)

4.2 everything() 返回未被選擇的所有列

當只是將幾列移到最前面,後面的可使用everything(),節省大量輸入時間。

msleep %>%
 select(conservation, everything()) %>% head(2)
# A tibble: 2 x 11
 conservation name  genus vore  order sleep_total sleep_rem sleep_cycle awake
 <chr>        <chr> <chr> <chr> <chr>       <dbl>     <dbl>       <dbl> <dbl>
1 lc           Chee~ Acin~ carni Carn~        12.1      NA            NA  11.9
2 NA           Owl ~ Aotus omni  Prim~        17         1.8          NA   7  
# ... with 2 more variables: brainwt <dbl>, bodywt <dbl>

 

五 更改列名字

5.1 select更改列名

msleep %>%
 select(animal = name, sleep_total) %>% head(2)
# A tibble: 2 x 2
 animal     sleep_total
 <chr>            <dbl>
1 Cheetah           12.1
2 Owl monkey        17  

注:select語句中更改,只留下select的列。

5.2 rename更改列名

msleep %>% 
 rename(animal = name) %>% head(2)
# A tibble: 2 x 11
 animal genus vore  order conservation sleep_total sleep_rem sleep_cycle awake
 <chr>  <chr> <chr> <chr> <chr>              <dbl>     <dbl>       <dbl> <dbl>
1 Cheet~ Acin~ carni Carn~ lc                  12.1      NA            NA  11.9
2 Owl m~ Aotus omni  Prim~ NA                  17         1.8          NA   7  
# ... with 2 more variables: brainwt <dbl>, bodywt <dbl>

以上兩種方式注意區分!

5.3 重新格式化所有列名

1)select_all()函式允許更改所有列,並以一個函式作為引數。

msleep %>%
 select_all(toupper) %>% head(2)
# A tibble: 2 x 11
 NAME  GENUS VORE  ORDER CONSERVATION SLEEP_TOTAL SLEEP_REM SLEEP_CYCLE AWAKE
 <chr> <chr> <chr> <chr> <chr>              <dbl>     <dbl>       <dbl> <dbl>
1 Chee~ Acin~ carni Carn~ lc                  12.1      NA            NA  11.9
2 Owl ~ Aotus omni  Prim~ NA                  17         1.8          NA   7  
# ... with 2 more variables: BRAINWT <dbl>, BODYWT <dbl>

toupper()使所有列名變成大寫形式,tolower()變成小寫。

 

2)建立函式替換

如果輸入檔案的列名較混亂,根據需求逐步替換。

msleep2 <- select(msleep, name, sleep_total, brainwt)
colnames(msleep2) <- c("Q1 name", "Q2 sleep total", "Q3 brain weight")
msleep2[1:3,]
# A tibble: 3 x 3
 `Q1 name`       `Q2 sleep total` `Q3 brain weight`
 <chr>                      <dbl>             <dbl>
1 Cheetah                     12.1           NA    
2 Owl monkey                  17              0.0155
3 Mountain beaver             14.4           NA  

目的把列名中的"Q1 name"改為"name","Q2 sleep total"改為"sleep_total" ...

A:去掉前面的Q1,Q2,Q3 ;

B:去掉Q1,Q2,Q3 與名稱的空格;

C:sleep total之間的空格使用下劃線替換。

msleep2 %>%
   select_all(~str_replace(., "Q[0-9]+", "")) %>%  #去掉Q1
select_all(~str_replace(., "^ ", "")) %>% #去掉名稱前面的空格
   select_all(~str_replace(., " ", "_")) #下劃線替換sleep total之間的空格
# A tibble: 83 x 3
  name                       sleep_total brain_weight
  <chr>                            <dbl>        <dbl>
1 Cheetah                           12.1     NA      
2 Owl monkey                        17        0.0155

搞定!

 

六 滿五贈二

6.1 刪除某些列

選擇的列前用“-”即可,函式用法與選擇一致。

 msleep %>%
  select(-(name:genus), -conservation,-(ends_with("e"))) %>% head(2)
# A tibble: 2 x 5
 order     sleep_total sleep_rem brainwt bodywt
 <chr>           <dbl>     <dbl>   <dbl>  <dbl>
1 Carnivora        12.1      NA   NA       50  
2 Primates         17         1.8  0.0155   0.48

6.2 行名稱改為第一列

某些資料框的行名並不是列,例如mtcars資料集:

 mtcars %>% head(2)

##                   mpg cyl disp hp drat   wt qsec vs am gear carb
## Mazda RX4         21.0   6 160 110 3.90 2.620 16.46 0 1   4   4
## Mazda RX4 Wag     21.0   6 160 110 3.90 2.875 17.02 0 1   4   4

使用 rownames_to_column()函式,行名改為列,且可指定列名稱。

mtcars %>% 
tibble::rownames_to_column("car_name") %>% head(2)
      car_name mpg cyl disp  hp drat    wt  qsec vs am gear carb
1     Mazda RX4  21   6  160 110  3.9 2.620 16.46  0  1    4    4
2 Mazda RX4 Wag  21   6  160 110  3.9 2.875 17.02  0  1    4    4

相信我,後面做資料鏈接(join)的時候,你會很希望行名是具體列的。

 

參考資料

《R資料科學》

https://r4ds.had.co.nz/introduction.html

https://suzanbaert.netlify.com/2018/01/dplyr-tutorial-1/

 

資料處理確實不如視覺化“好玩”,但是視覺化的資料大多都需要前期處理,這個“檻”一起慢慢跨過去!

 

◆ ◆ ◆ ◆ ◆

【覺得不錯,右下角點個“在看”,期待您的轉發,謝謝!】

&n