資料預處理之抽取文字資訊(2)
摘要:大資料技術與我們日常生活越來越緊密,要做大資料,首要解決資料問題。原始資料存在大量不完整、不一致、有異常的資料,嚴重影響到資料建模的執行效率,甚至可能導致模型結果的偏差,因此要資料預處。資料預處理主要是將原始資料經過文字抽取、資料清理、資料整合、資料處理、資料變換、資料降維等處理後,不僅提高了資料質量,而且更好的提升演算法模型效能。資料預處理在資料探勘、自然語言處理、機器學習、深度學習演算法中起著重要的作用。(本文原創,轉載必須註明出處.)
1 資料型別與資料採集
通常說的資料指的的數字、圖表資訊這些。在大資料領域所謂的資料總體包括結構化資料、半結構化資料和非結構化資料。
結構化資料
結構化的資料是指可以使用關係型資料庫表示和儲存,表現為二維形式的資料。一般特點是:資料以行為單位,一行資料表示一個實體的資訊,每一行資料的屬性是相同的。比如:
id | name | age | gender |
---|---|---|---|
1 | 張三 | 12 | 男 |
2 | 李花 | 13 | 女 |
3 | 王五 | 18 | 男 |
- 資料特點:關係模型資料,關係資料庫表示。
- 常見格式:比如MySQL、Oracle、SQL Server等。
- 應用場合:資料庫、系統網站、資料備份、ERP等。
- 資料採集:DB匯出、SQL等方式。
結構化的資料的儲存和排列是很有規律的,這對查詢和修改等操作很有幫助。但是,它的擴充套件性不好。
半結構化資料
半結構化資料是結構化資料的一種形式,它並不符合關係型資料庫或其他資料表的形式關聯起來的資料模型結構,但包含相關標記,用來分隔語義元素以及對記錄和欄位進行分層。因此,它也被稱為自描述的結構。半結構化資料,屬於同一類實體可以有不同的屬性,即使他們被組合在一起,這些屬性的順序並不重要。常見的半結構資料有XML如下:
<person>
<name>李花</name>
<age>13</age>
<gender>女</gender>
</person>
- 資料特點:非關係模型資料,還有一定的格式。
- 常見格式:比如Email、HTML、XML、JSON等。
- 應用場合:郵件系統、檔案系統、新聞網站等。
- 資料採集:網路爬蟲、資料解析等方式。
不同的半結構化資料的屬性的個數是不定的。有些人說半結構化資料是以樹或者圖的資料結構儲存的資料,上面的例子中,標籤是樹的根節點,和標籤是子節點。通過這樣的資料格式,可以自由地表達很多有用的資訊,包括自我描述資訊(元資料)。所以,半結構化資料的擴充套件性是很好的。
非結構化資料
就是沒有固定結構的資料。各種文件、圖片、視訊/音訊等都屬於非結構化資料。對於這類資料,我們一般直接整體進行儲存,而且一般儲存為二進位制的資料格式。如下所示:
- 資料特點:沒有固定格式的資料
- 常見格式:Word、PDF、PPT、圖片、音視訊等。
- 應用場合:圖片識別、人臉識別、醫療影像、文字分析等。
- 資料採集:網路爬蟲、資料存檔等方式。
2 常見的文字抽取方法
針對資料不同形式,通過特定方式的資料採集方式(文件下載、資料庫匯出、網路爬蟲、語音收集、圖片解析等等)獲取資料,無論是結構化的資料庫檔案、半結構化的網頁資料,還是非結構化的圖片、音視訊。我們最終的目的都是將資料傳入到電腦之中,通過演算法模型挖掘其潛在的價值,為最終的AI技術做支撐。不同的是,在結構化和半結構化資料資料整合過程中,我們可以提取相關文字資訊,做進一步的資料預處理;而非結構化的圖片、音視訊我們採用一定的技術手段,獲取其對應的資料點矩陣。這一點不太容易理解,我們比如說想解析一張圖片的資料,我們知道圖片是有長寬高組成的,還包括紅藍綠三種基本色。那麼我們就找到對應的多維特徵,採用資料點佔位表示,比如:
圖片名 | 長(bit) | 寬(bit) | 紅 | 綠 | 藍 |
---|---|---|---|---|---|
貓1 | 12 | 100 | 0 | 0 | 1 |
狗2 | 101 | 234 | 1 | 1 | 1 |
豬3 | 202 | 24 | 0 | 1 | 0 |
上面就資料表示貓1這張圖片,長寬位點(12,100)處只有藍色構成;狗2這張圖片,長寬位點(101,234)處有紅綠藍3中色構成;豬3這張圖片,長寬位點(202,24)處只有綠構成。這就是非結構資料圖片轉化為數值型資料的原理。完整流程資料探勘的流程圖如下所示:
我根據不同的資料型別,採用對應的資料採集方式獲取目標資料。這時候的資料質量很差,存在文字格式不同,資料表示形式不同等諸多問題。這裡我們單純的考慮文字資訊的處理,就文字資訊而言,你採集的資料可能是網頁、資料庫檔案、pdf文件、word文件等等。我們想去處理這些資料,還需要對資料進行整合即轉化為統一的資料格式,這裡我們就需要文字資訊抽取,常見的抽取方式包括以下幾個內容:線上格式轉換工具、office內建格式轉換、自己開發文字抽取工具。詳見下圖:
經過實際操作會發現採用線上格式轉換工具存在幾個弊端,其限制檔案轉化的資料,要麼就是收費的;而採用本地的office自帶文件,一個個另存為文字,肯定不現實。基於上述情況,我們對工具抽取的弊端總結如下:
- 格式轉換後,識別亂碼較多
- 不支援或者限制支援批量處理
- 批量轉化收費問題
- 格式轉換後的txt檔案存在編碼問題
- 生成檔名一堆數字亂碼
- 操作不夠靈活便捷
我們針對以上問題,就去尋求解決方式,那就是自己動手豐衣足食,我們自己去打造批量文字抽取問題,我們期待效果是:
- 支援PDF/Word等多格式文字抽取
- 自動過濾不符合指定格式的檔案
- 生成的目標檔案與原檔案目錄一致
- 生成文件採用統一的編碼格式儲存(如:UTF-8 )
- 支援預設儲存路徑和自定義儲存路徑
3 抽取Word文件文字
做word文件抽取工作,我們執行環境是在win10-64bit下,python3.5,Anaconda4.4版本下執行的,所使用的外掛是win32com。下載地址:https://pan.baidu.com/s/1-2BsiTs8XjMIe5Gnh_GFjw 密碼: 7j3t
預裝完win32com以後,以下程式碼便完成抽取word文字資訊。
演算法思路:
- 定義檔案路徑和轉存路徑:split
- 修改新的檔名:fnmatch
- 設定完整的儲存路徑:join
- 啟動應用程式格式轉換:Dispatch
- 儲存文字:SaveAs
演算法流程:
程式碼實現:
#coding=utf-8
"""
Description: Word檔案轉化TXT文字
Author:伏草惟存
Prompt: code in Python3 env
Install package: pip install pypiwin32
"""
import os,fnmatch
from win32com import client as wc
from win32com.client import Dispatch
'''
功能描述:word檔案轉存txt檔案,預設儲存當前路徑下;使用者可以指定儲存檔案路徑。
引數描述:1 filePath:檔案路徑 2 savePath: 指定儲存路徑
'''
def Word2Txt(filePath,savePath=''):
# 1 切分檔案上級目錄和檔名
dirs,filename = os.path.split(filePath)
# print(dirs,'\n',filename)
# 2 修改轉化後的檔名
new_name = ''
if fnmatch.fnmatch(filename,'*.doc'):
new_name = filename[:-4]+'.txt'
elif fnmatch.fnmatch(filename,'*.docx'):
new_name = filename[:-5]+'.txt'
else: return
print('->',new_name)
# 3 檔案轉化後的儲存路徑
if savePath=='': savePath = dirs
else: savePath = savePath
word_to_txt = os.path.join(savePath,new_name)
print('->',word_to_txt)
# 4 載入處理應用,word轉化txt
wordapp = wc.Dispatch('Word.Application')
mytxt = wordapp.Documents.Open(filePath)
mytxt.SaveAs(word_to_txt,4)
mytxt.Close()
if __name__=='__main__':
filepath = os.path.abspath(r'../dataSet/filename.doc')
# savepath = ''
Word2Txt(filepath)
4 抽取PDF文件文字
演算法思路:
- 定義檔案路徑和轉存路徑:split
- 修改新的檔名:fnmatch
- 設定完整的儲存路徑:join
- 啟動應用程式格式轉換:Dispatch
- 儲存文字:SaveAs
演算法流程:
程式碼實現:
# coding=utf-8
"""
Description: PDF檔案轉化TXT文字
Author:伏草惟存
Prompt: code in Python3 env
"""
import os,fnmatch
from win32com import client as wc
from win32com.client import Dispatch,gencache
'''
功能描述:pdf檔案轉化txt文字
引數描述:1 filePath:檔案路徑 2 savePath: 指定儲存路徑
'''
def Pdf2Txt(filePath,savePath=''):
# 1 切分檔案上級目錄和檔名
dirs,filename = os.path.split(filePath)
# print('目錄:',dirs,'\n檔名:',filename)
# 2 修改轉化後的檔名
new_name = ""
if fnmatch.fnmatch(filename,'*.pdf') or fnmatch.fnmatch(filename,'*.PDF'):
new_name = filename[:-4]+'.txt' # 擷取".pdf"之前的檔名
else: return
print('新的檔名:',new_name)
# 3 檔案轉化後的儲存路徑
if savePath=="": savePath = dirs
else: savePath = savePath
pdf_to_txt = os.path.join(savePath,new_name)
print('儲存路徑:',pdf_to_txt)
# 4 載入處理應用,pdf轉化txt
wordapp = wc.Dispatch('Word.Application')
mytxt = wordapp.Documents.Open(filePath)
mytxt.SaveAs(pdf_to_txt,4)
mytxt.Close()
if __name__=='__main__':
# 使用絕對路徑
filePath = os.path.abspath(r'../dataSet/Corpus/pdftotxt/2018年世界新聞自由日.pdf')
# savePath = r'E:\\'
Pdf2Txt(filePath)
5 文字抽取工具與編碼
演算法思路:
- 定義資料夾路徑和轉存夾路徑:split
- 修改新的檔名:TranType(filename, typename)、fnmatch
- 設定完整的儲存路徑:join
- 啟動應用程式格式轉換:Dispatch
- 儲存文字:SaveAs
程式碼實現
#coding=utf-8
"""
Description: 多文件格式轉換工具
Author:伏草惟存
Prompt: code in Python3 env
"""
import os,fnmatch
from win32com import client as wc
from win32com.client import Dispatch,gencache
'''
功能描述:抽取檔案文字資訊
引數描述:1 filePath:檔案路徑 2 savePath: 指定儲存路徑
'''
def Files2Txt(filePath,savePath=''):
try:
# 1 切分檔案上級目錄和檔名
dirs,filename = os.path.split(filePath)
# print('目錄:',dirs,'\n檔名:',filename)
# 2 修改轉化後的檔名
typename = os.path.splitext(filename)[-1].lower() # 獲取字尾
new_name = TranType(filename,typename)
# print('新的檔名:',new_name)
# 3 檔案轉化後的儲存路徑
if savePath=="": savePath = dirs
else: savePath = savePath
new_save_path = os.path.join(savePath,new_name)
print('儲存路徑:',new_save_path)
# 4 載入處理應用
wordapp = wc.Dispatch('Word.Application')
mytxt = wordapp.Documents.Open(filePath)
mytxt.SaveAs(new_save_path,4)
mytxt.Close()
except Exception as e:
pass
'''
功能描述:根據檔案字尾修改檔名
引數描述:1 filePath:檔案路徑 2 typename 檔案字尾
返回資料:new_name 返回修改後的檔名
'''
def TranType(filename,typename):
# 新的檔名稱
new_name = ""
if typename == '.pdf' : # pdf->txt
if fnmatch.fnmatch(filename,'*.pdf') :
new_name = filename[:-4]+'.txt' # 擷取".pdf"之前的檔名
else: return
elif typename == '.doc' or typename == '.docx' : # word->txt
if fnmatch.fnmatch(filename, '*.doc') :
new_name = filename[:-4]+'.txt'
elif fnmatch.fnmatch(filename, '*.docx'):
new_name = filename[:-5]+'.txt'
else: return
else:
print('警告:\n您輸入[',typename,']不合法,本工具支援pdf/doc/docx格式,請輸入正確格式。')
return
return new_name
if __name__ == '__main__':
filePath1 = os.path.abspath(r'../dataSet/Corpus/wordtotxt/一種改進的樸素貝葉斯文字分類方法研究.doc')
filePath2 = os.path.abspath(r'../dataSet/Corpus/pdftotxt/改進樸素貝葉斯文字分類方法研究.pdf')
filePath3 = os.path.abspath(r'../dataSet/Corpus/wordtotxt/科技專案資料探勘決策架構.docx')
Files2Txt(filePath3)
遍歷讀取檔案
- 遍歷檔案的類TraversalFun : TraversalDir、 AllFiles
- 遍歷目錄檔案TraversalDir : AllFiles(self.rootDir)
- 遞迴遍歷檔案AllFiles: AllFiles(self,rootDir)
- 判斷是否為檔案isfile :打印出檔名
- 判斷是否是目錄isdir :遞迴遍歷
遍歷檔案原始碼實現
# coding=utf-8
"""
Description: 遍歷讀取檔名
Author:伏草惟存
Prompt: code in Python3 env
"""
import os,time
'''
功能描述:遍歷目錄處理子檔案
引數描述: 1 rootDir 目標檔案的根目錄
'''
class TraversalFun():
# 1 初始化
def __init__(self,rootDir):
self.rootDir = rootDir # 目錄路徑
# 2 遍歷目錄檔案
def TraversalDir(self):
TraversalFun.AllFiles(self,self.rootDir)
# 3 遞迴遍歷所有檔案,並提供具體檔案操作功能
def AllFiles(self,rootDir):
# 返回指定目錄包含的檔案或資料夾的名字的列表
for lists in os.listdir(rootDir):
# 待處理資料夾名字集合
path = os.path.join(rootDir, lists)
# 核心演算法,對檔案具體操作
if os.path.isfile(path):
print(os.path.abspath(path))
# 遞迴遍歷檔案目錄
elif os.path.isdir(path):
TraversalFun.AllFiles(self,path)
if __name__ == '__main__':
time_start=time.time()
# 根目錄檔案路徑
rootDir = r"../dataSet/Corpus/EnPapers"
tra=TraversalFun(rootDir) # 預設方法引數列印所有檔案路徑
tra.TraversalDir() # 遍歷檔案並進行相關操作
time_end=time.time()
print('totally cost',time_end-time_start,'s')
6 實戰案例:遍歷檔案批量抽取新聞文字內容
演算法思路
- 引用外部文字抽取模組:import ExtractTxt as ET
- 引數方法使用:TraversalFun(rootDir,ET.Files2Txt,saveDir)
- 建立儲存根目錄:os.path.abspath
- 遞迴遍歷檔案:func(path, save_dir)
原始碼實現
# coding=utf-8
"""
Description: 批量文件格式自動轉化txt
Author:伏草惟存
Prompt: code in Python3 env
"""
import ExtractTxt as ET
import os,time
'''
功能描述:遍歷目錄,對子檔案單獨處理
引數描述:1 rootDir 根目錄 2 deffun:方法引數 3 saveDir: 儲存路徑
'''
class TraversalFun():
# 1 初始化
def __init__(self,rootDir,func=None,saveDir=""):
self.rootDir = rootDir # 目錄路徑
self.func = func # 引數方法
self.saveDir = saveDir # 儲存路徑
# 2 遍歷目錄檔案
def TraversalDir(self):
# 切分檔案上級目錄和檔名
dirs,latername = os.path.split(self.rootDir)
# print(rootDir,'\n',dirs,'\n',latername)
# 儲存目錄
save_dir = ""
if self.saveDir=="": # 預設檔案儲存路徑
save_dir = os.path.abspath(os.path.join(dirs,'new_'+latername))
else: save_dir = self.saveDir
# 建立目錄檔案
if not os.path.exists(save_dir): os.makedirs(save_dir)
print("儲存目錄:\n"+save_dir)
# 遍歷檔案並將其轉化txt檔案
TraversalFun.AllFiles(self,self.rootDir,save_dir)
# 3 遞迴遍歷所有檔案,並提供具體檔案操作功能
def AllFiles(self,rootDir,save_dir=''):
# 返回指定目錄包含的檔案或資料夾的名字的列表
for lists in os.listdir(rootDir):
# 待處理資料夾名字集合
path = os.path.join(rootDir, lists)
# 核心演算法,對檔案具體操作
if os.path.isfile(path):
self.func(os.path.abspath(path),os.path.abspath(save_dir))
# 遞迴遍歷檔案目錄
if os.path.isdir(path):
newpath = os.path.join(save_dir, lists)
if not os.path.exists(newpath):
os.mkdir(newpath)
TraversalFun.AllFiles(self,path,newpath)
if __name__ == '__main__':
time_start=time.time()
# 根目錄檔案路徑
rootDir = r"../dataSet/Corpus/EnPapers"
# saveDir = r"./Corpus/TxtEnPapers"
tra=TraversalFun(rootDir,ET.Files2Txt) # 預設方法引數列印所有檔案路徑
tra.TraversalDir() # 遍歷檔案並進行相關操作
time_end=time.time()
print('totally cost',time_end-time_start,'s')