使用Pandas: str.replace() 進行文本清洗


前段時間參加了Kaggle上的Mercari Price Suggestion Challenge比賽,收獲良多,過些時候准備進行一些全面的總結,本篇文章先談一個比賽中用到的小技巧。

這個比賽數據中有一個特征叫做 "item_description",大致是一些商品描述,比如什么時候買的、新舊程度如何、什么牌子的等等。因為大部分都是Mercari這個網站(這個類似於國內的二手商品交易網站)上的用戶自己填的商品描述,所以是極盡雜亂之能事,會出現很多誇張的符號,比如這樣:


另外的一大問題是用語規范不統一,比如 $1.100$1.1 其實是一個意思,然而在對文本進行特征提取時就會被當成兩個特征,這會使特征變得過於稀疏,對模型的效果也會產生影響。所幸Pandas中提供了str.replace()這個方法,可以高效處理此類問題。


str.replace()的作用基本與re.sub()等同,區別在於re.sub()一次只能處理一個字符串,而str.replace()可以一次處理一整個Series,因而效率要高很多。str.replace()的正式形式為 Series.str.replace(pat, repl) ,其中pat為想要尋找的模式,一般為正則表達式,repl為要替換進去的字符串或函數。

下面是幾個簡單的例子,X代表一個Series,repl皆為字符串:

X.str.replace(r"iphone\s+7", "iphone7")  #為了將iphone7視為一個詞,把iphone 7轉換為iphone7,去除空格。
X.str.replace(r"16gbiphone", "16gb iphone")  #將16gbiphone轉換無16gb iphone,增加空格。
X.str.replace(r"fl\s?\.?\s?oz", "floz")  #將fl.oz或fl . oz轉換為floz

如果是一些比較復雜的情況,則需要將repl自定義為函數:

1) 將1.101000變為1.101,即將后面的"0"去掉。

remove0 = lambda m:m.group(0).rstrip("0")
X.str.replace(r"\d\.\d*[1-9]+0+", remove0)

上例中將repl定義為一個匿名函數,m.group(0)為匹配到的所有字符串,注意其不會匹配到1.000的情況,因為pat中存在[1-9]。


2) 將1.000kg變為1kg,這里因為要去除的.0兩個字符位於中間,所以無法用上面的rstrip()

table1 = str.maketrans("","","0.")
remove1 = lambda m:m.group(0).translate(table1)
X.str.replace(r"\.0+[a-z]+", remove1)

上例中使用str.maketrans()方法指定想要刪除的字符,再用translate()刪除。這是python 3的寫法,python 2中可直接使用translate()

# python 2
remove1 = lambda m:m.group(0).translate(None,"0.")
X.str.replace(r"\.0+[a-z]+", remove1)

3) 將0.0300kg轉換為0.03kg。這里由於0.03本身存在0,所以不能用str.maketrans()了,因為會將所有0都刪除。所以這里用兩個正則表達式分別找到0.03和kg,再拼接起來:

def remove2(data):
    al1 = re.findall(r"\d+\.\d*[1-9]+0+",data.group(0))
    al2 = re.findall(r"[a-z]+",data.group(0))
    return al1[0].rstrip("0") + al2[0]

X.str.replace(r"\d+\.\d*[1-9]+0+[a-z]+", remove2)

4) 將1.100%轉換為1 100%, 這么做的目的是1.100%可能會被轉換為一個詞,而實際想要提取的肯定只有100%:

def remove3(data):
    al1 = re.findall(r"\d+(?=\.)", data.group(0))  # 這里使用了零寬斷言(?=),是為了去除”.“
    al2 = re.findall(r"100%", data.group(0))
    return al1[0]+" "+al2[0]

X.str.replace(r"\d+\.100%", remove3)   

5) 商品中有很多衣服鞋子之類的,一般都標有尺碼,比如3",15”等。這里要把后面的尺碼符號‘ ” ’提取出來並用“colon”表示,讓模型識別出前面的數字3和15是代表尺碼大小。

def findcolon(data):
    al1 = re.findall(r'\d{1,2}\.\d{1,3}|\d{1,2}|1\d{2}', data.group(0)) 
    return al1[0]+" colon "

X.str.replace(r'(?:\d{1,2}\.\d{1,3}|\d{1,2}|1\d{2})(?:\s?\")', findcolon) # 匹配2.3“, 55", 132"等,轉換為2.3 colon

由此,本文結合比賽中的例子介紹了幾種清洗文本的方法,另外Pandas中還提供了其他很多有用的處理文本的方法,詳見文檔 Working with Text Data





/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM