iT邦幫忙

2023 iThome 鐵人賽

DAY 6
0
AI & Data

用R語言玩轉文字探勘系列 第 6

[Day 6] R語言與字串處理: 利用stringr

  • 分享至 

  • xImage
  •  

字串處理情境介紹

文字探勘的諸多應用如情緒分析、文本分類,聽起來都很美好,但在分析資料以前,首先要有乾淨資料。舉例來說,若我們想分析歷屆台灣總統的演講稿,在事前我們可能要先做這些準備:保留講稿中「台灣」和「臺灣」其中一種用法、刪除原文中的換行符號、整理民國與西元日期格式、消除空格例如以前可能會出現挪抬等。

上述提到的小任務,全部都是字串處理的範疇。當然,你可能會想說,你手上的資料已經非常乾淨,根本沒必要走過這些步驟!其實,就算不是文字探勘、就算資料已經足夠乾淨,但字串處理的使用情境非常生活化,它仍然能夠在意想不到的地方幫上你。

在實際開始寫程式之前,我們先來看幾個日常任務:

  • 字串偵測:當手上有一包客戶使用產品回饋資料,想集中分析主力產品ABC,這時使用篩選功能,其實就是字串偵測(string detection)
  • 字串取代:平常使用Google document或者Microsoft word的時候,時常會用到「尋找與取代」功能,其中的取代就是字串取代(string substitution)
  • 字串連接:如果我們想把Google spreadsheet裡不同欄位拼在一起,通常會用&函數,這個函數的意義就是字串連接(string concatenation)

除了這些實例,還有更多看似不起眼、卻在工作中反覆出現的小任務,例如英文大小寫轉換、計算特定字串出現次數、切割文章與文字等,都屬於字串處理。而這些任務,全都可以交給stringr套件解決。

stringr官方介紹頁面中就提到,「在R語言裡,字串可能不那麼引人注目或者高調,但在許多資料清理和預處理的任務中,它們確實扮演了很大的角色,」同時,它將stringr稱為用於常見字串操作,簡單且具有一致性的(consistent)「包裝」(wrapper)。為什麼說它是一種具有一致性的包裝呢?下方介紹說分明。

stringr套件介紹

dplyrtidyrtidytext等套件一樣,stringr同屬tidyverse生態系,它不只功能多元,幾乎可以將字串處理任務一網打盡,更關鍵的是,stringr在設計時就處理掉一個使用者的重要痛點:「函數名稱不好背。」

打開stringr的官方說明頁面,你可以很快發現,它的函數幾乎都是用str_()開頭,這也就是前面提的一致性。不管是哪種字串處理任務,利用邏輯統一的命名方式,包裝每個套件中的函數。

如果你曾接觸過base R就知道,R語言原生的字串處理函數非常不好記。舉例來說,base R有兩個函數grep()grepl(),前者可以比對出符合特定模式(pattern)的字串,並告訴你是第幾個,後者則會給予TRUEFALSE的回饋。

string <- c("text mining","mine")
grep(pattern = "mine", x = string)

## [1] 2

grepl(pattern = "mine", x = string)

## [1] FALSE  TRUE

stringr套件中,就只有一個簡單的str_detect()要記。

string <- c("text mining","mine")
str_detect(string, pattern = "mine")

## [1] FALSE  TRUE

再舉一例,sub()gsub()可以替換(replace)字串,前者只能替換字串中第一次出現者,後者則可以全數替換。

string2 <- c("text","text and text")
sub(pattern = "text", replacement = "data", x = string2)

## [1] "data"          "data and text"

gsub(pattern = "text", replacement = "data", x = string2)

## [1] "data"          "data and data"

只是,在記函數名稱的時候,常常會忘記到底要用sub()還是gsub(),人腦記憶體就消耗在這裡。在stringr裡面,有效果相同的函數,但命名邏輯更加一致,且名稱又很直觀,它們分別是str_replace()str_replace_all()

string2 <- c("text","text and text")
str_replace(string = string2, pattern = "text", replacement = "data")

## [1] "data"          "data and text"

str_replace_all(string = string2, pattern = "text", replacement = "data")

## [1] "data"          "data and data"

不只是命名而已,我們也會發現,stringr函數的參數(argument)順序永遠都一樣,先是想要處理的字串,接著則是想要比對的模式,接續才會是其他會用到的參數。stringr就是靠著函數取名邏輯一致名稱直觀好記參數清晰功能多樣,成功擄獲使用者芳心。

底下我們整理出stringr中常用函數,以及它們能夠完成的任務。

stringr函數

我們來看stringr當中有些什麼函數吧:

其中,有_all()後綴的函數,使用時就會返回多個結果,來看以下實際例子:

str_replace(c("BTOB", "BTS", "BACKSTREET BOYS"), "B", "A")

## [1] "ATOB"            "ATS"             "AACKSTREET BOYS"

str_replace_all(c("BTOB", "BTS", "BACKSTREET BOYS"), "B", "A")

## [1] "ATOA"            "ATS"             "AACKSTREET AOYS"

此外,使用stringr函數時還有一個重點:注意函數輸出的資料結構為何。以str_extract()來說,因為只會擷取第一個符合模式的字串,因此都只會返回一個字串,下方例子中輸出格式為向量(vector);str_extract_all()則會返回所有字串,因此輸出格式就會是列表(list)。

在以資料框(dataframe)為主的環境下處理資料時,若是在mutate()使用相關函數時,就要注意函數運用結果,會不會讓欄位從單純的字串變成列表,這樣就會影響接下來dplyr動詞還有其他tidyverse函數的運用。

library(tidyverse)
tibble(name = c("BTOB", "BTS", "BACKSTREET BOYS")) %>%
  mutate(extract = str_extract(name, "B.*?S"))

## # A tibble: 3 × 2
##   name            extract
##   <chr>           <chr>  
## 1 BTOB            <NA>   
## 2 BTS             BTS    
## 3 BACKSTREET BOYS BACKS

tibble(name = c("BTOB", "BTS", "BACKSTREET BOYS")) %>%
  mutate(extract = str_extract_all(name, "B.*?S"))

## # A tibble: 3 × 2
##   name            extract  
##   <chr>           <list>   
## 1 BTOB            <chr [0]>
## 2 BTS             <chr [1]>
## 3 BACKSTREET BOYS <chr [2]>

從這個例子中,就能看出str_extract()產出的欄位為字串,str_extract_all()產出的欄位為列表欄位。使用str_split()時,也會遇到相似情況。

str_split(c("BTOB,BTS", "Apink,April,AOA"), ",")

## [[1]]
## [1] "BTOB" "BTS" 
## 
## [[2]]
## [1] "Apink" "April" "AOA"

tibble(name = c("BTOB,BTS", "Apink,April,AOA")) %>%
  mutate(name2 = strsplit(name, ","))

## # A tibble: 2 × 2
##   name            name2    
##   <chr>           <list>   
## 1 BTOB,BTS        <chr [2]>
## 2 Apink,April,AOA <chr [3]>

利用上述這些stringr()中的函數,就可以解決非常多字串處理的問題了!


上一篇
[Day 5] R語言與正規表達式: 進階語法和實例
下一篇
[Day 7] R語言中的字串資料、路徑與編碼
系列文
用R語言玩轉文字探勘30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言