Python連接HDFS實(shí)現(xiàn)文件上傳下載及Pandas轉(zhuǎn)換文本文件到CSV操作
1. 目標(biāo)
通過(guò)hadoop hive或spark等數(shù)據(jù)計(jì)算框架完成數(shù)據(jù)清洗后的數(shù)據(jù)在HDFS上
爬蟲(chóng)和機(jī)器學(xué)習(xí)在Python中容易實(shí)現(xiàn)
在Linux環(huán)境下編寫(xiě)Python沒(méi)有pyCharm便利
需要建立Python與HDFS的讀寫(xiě)通道
2. 實(shí)現(xiàn)
安裝Python模塊pyhdfs
版本:Python3.6, hadoop 2.9
讀文件代碼如下
from pyhdfs import HdfsClient
client=HdfsClient(hosts='ghym:50070')#hdfs地址
res=client.open('/sy.txt')#hdfs文件路徑,根目錄/
for r in res:
line=str(r,encoding='utf8')#open后是二進(jìn)制,str()轉(zhuǎn)換為字符串并轉(zhuǎn)碼
print(line)
寫(xiě)文件代碼如下
from pyhdfs import HdfsClient
client=HdfsClient(hosts='ghym:50070',user_name='hadoop')#只有hadoop用戶(hù)擁有寫(xiě)權(quán)限
str='hello world'
client.create('/py.txt',str)#創(chuàng)建新文件并寫(xiě)入字符串
上傳本地文件到HDFS
from pyhdfs import HdfsClient
client = HdfsClient(hosts='ghym:50070', user_name='hadoop')
client.copy_from_local('d:/pydemo.txt', '/pydemo')#本地文件絕對(duì)路徑,HDFS目錄必須不存在
3. 讀取文本文件寫(xiě)入csv
Python安裝pandas模塊
確認(rèn)文本文件的分隔符
# pyhdfs讀取文本文件,分隔符為逗號(hào),
from pyhdfs import HdfsClient
client = HdfsClient(hosts='ghym:50070', user_name='hadoop')
inputfile=client.open('/int.txt')
# pandas調(diào)用讀取方法read_table
import pandas as pd
df=pd.read_table(inputfile,encoding='gbk',sep=',')#參數(shù)為源文件,編碼,分隔符
# 數(shù)據(jù)集to_csv方法轉(zhuǎn)換為csv
df.to_csv('demo.csv',encoding='gbk',index=None)#參數(shù)為目標(biāo)文件,編碼,是否要索引
補(bǔ)充知識(shí):記 讀取hdfs 轉(zhuǎn) pandas 再經(jīng)由pandas轉(zhuǎn)為csv的一個(gè)坑
工作流程是這樣的:
讀取 hdfs 的 csv 文件,采用的是 hdfs 客戶(hù)端提供的 read 方法,該方法返回一個(gè)生成器。
將讀取到的數(shù)據(jù)按 逗號(hào) 處理,變?yōu)橐粋€(gè)二維數(shù)組。
將二維數(shù)組傳給 pandas,生成 df。
經(jīng)若干處理后,將 df 轉(zhuǎn)為 csv 文件并寫(xiě)入hdfs。
問(wèn)題是這樣的:
正常的數(shù)據(jù):
ZERO,MEAN,STD,CV,INC,OPP,CS,IS_OUTNET
0,9.233,2.445,0.265,1.202,241,1,0
0,8.667,1.882,0.217,1.049,179,1,0
三行數(shù)據(jù),正常走流程,沒(méi)有任何問(wèn)題。
異常數(shù)據(jù):
ZERO,MEAN,STD,CV,INC,OPP,CS,IS_OUTNET,probability,prediction
0,9.233,2.445,0.265,1.202,241,1,0,'[0.9653901649086855,0.03460983509131456]',0.0
0,8.667,1.882,0.217,1.049,179,1,0,'[0.9653901649086855,0.03460983509131456]',0.0
在每一行中都會(huì)有一個(gè)數(shù)組類(lèi)似的數(shù)據(jù),有一對(duì)引號(hào)包起來(lái),中間存在逗號(hào),不可以拆分。
為此,我的做法如下:
匹配逗號(hào)是被成對(duì)引號(hào)包圍的字符串。
將匹配到的字符串中的逗號(hào)替換為特定字符。
將替換后的新字符串替換回原字符串。
在將原字符串中的特定字符串替換為逗號(hào)。
本來(lái)這樣做沒(méi)有什么問(wèn)題,但是在經(jīng)由pandas轉(zhuǎn)為csv的時(shí)候,發(fā)現(xiàn)原來(lái)帶引號(hào)的字符串變?yōu)榱饲昂蟾鲙齻€(gè)引號(hào)。
源數(shù)據(jù):

處理后的數(shù)據(jù):

方法如下:

仔細(xì)研究對(duì)比了下數(shù)據(jù),發(fā)現(xiàn)數(shù)據(jù)里的引號(hào)其實(shí)只是在純文本文件中用來(lái)標(biāo)識(shí)其為字符串,并不應(yīng)該存在于實(shí)際數(shù)據(jù)中。

而我每次匹配后都是原封不動(dòng)替換回去,譬如:
源數(shù)據(jù):
"[0.9653901649086855,0.03460983509131456]"
匹配替換后:
"[0.9653901649086855${dot}0.03460983509131456]"
這樣傳給pandas,它就會(huì)認(rèn)為這個(gè)數(shù)據(jù)是帶引號(hào)的,在重新轉(zhuǎn)為csv的時(shí)候,就會(huì)進(jìn)行轉(zhuǎn)義等操作,導(dǎo)致多出很多引號(hào)。
所以解決辦法就是在替換之前,將匹配時(shí)遇到的引號(hào)也去掉:
PATTERN = '(?<=(?P<quote>[\'\"]))([^,]+,[^,]+)+?(?=(?P=quote))'
中間 ([^,]+,[^,]+)+? 要用+?,因?yàn)楸仨毚_定是有這樣的組合才可以,并且非貪婪模式,故不可 ? 或者 *?

(ps:為了方便后面引用前面的匹配,我在環(huán)視匹配中創(chuàng)建了一個(gè)組)
再來(lái)個(gè)整體效果:

為了說(shuō)明效果,引用pandas的自帶讀取csv方法:

可以看到pandas讀取出的該位置數(shù)據(jù)也是字符串,引號(hào)正是作為一個(gè)字符串聲明而存在。
再次修改正則:
def split_by_dot_escape_quote(string):
"""
按逗號(hào)分隔字符串,若其中有引號(hào),將引號(hào)內(nèi)容視為整體
"""
# 匹配引號(hào)中的內(nèi)容,非貪婪,采用正向肯定環(huán)視,
# 當(dāng)左引號(hào)(無(wú)論單雙引)被匹配到,放入組quote,
# 中間的內(nèi)容任意,但是要用+?,非貪婪,且至少有一次匹配到字符,
# 若*?,則匹配0次也可,并不會(huì)匹配任意字符(環(huán)視只匹配位置不匹配字符),
# 由于在任意字符后面又限定了前面匹配到的quote,故只會(huì)匹配到",
# +?則會(huì)限定前面必有字符被匹配,故"",或引號(hào)中任意值都可匹配到
pattern = re.compile('(?=(?P<quote>[\'\"])).+?(?P=quote)')
rs = re.finditer(pattern, string)
for data in rs:
# 匹配到的字符串
old_str = data.group()
# 將匹配到的字符串中的逗號(hào)替換為特定字符,
# 以便還原到原字符串進(jìn)行替換
new_str = old_str.replace(',', '${dot}')
# 由于匹配到的引號(hào)僅為字符串申明,并不具有實(shí)際意義,
# 需要把匹配時(shí)遇到的引號(hào)都去掉,只替換掉當(dāng)前匹配組的引號(hào)
new_str = re.sub(data.group('quote'), '', new_str)
string = string.replace(old_str, new_str)
sps = string.split(',')
return map(lambda x: x.replace('${dot}', ','), sps)
s = '"2011,603","3510006998","F","5","5","0",""'
print(list(split_by_dot_escape_quote(s)))
運(yùn)行結(jié)果如下:

之前想的正則有些復(fù)雜,反而偏離了本意,還是對(duì)正則的認(rèn)識(shí)不夠深。
以上這篇Python連接HDFS實(shí)現(xiàn)文件上傳下載及Pandas轉(zhuǎn)換文本文件到CSV操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
MySQLdb ImportError: libmysqlclient.so.18解決方法
這篇文章主要介紹了MySQLdb ImportError: libmysqlclient.so.18解決方法,需要的朋友可以參考下2014-08-08
tensorflow轉(zhuǎn)onnx的實(shí)現(xiàn)方法
本文主要介紹了tensorflow轉(zhuǎn)onnx的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
Python數(shù)據(jù)類(lèi)型詳解(二)列表
本文給大家詳細(xì)介紹的是Python數(shù)據(jù)類(lèi)型中的列表(list),非常的簡(jiǎn)單實(shí)用,有需要的小伙伴可以參考下2016-05-05
Python實(shí)現(xiàn)簡(jiǎn)單的四則運(yùn)算計(jì)算器
相信大家在學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)時(shí),就學(xué)習(xí)了簡(jiǎn)單四則運(yùn)算表達(dá)式求解的一個(gè)算法,可惜一直沒(méi)有自己動(dòng)手實(shí)現(xiàn)過(guò)這個(gè)算法。最近重拾數(shù)據(jù)結(jié)構(gòu)與算法,恰巧又正在用Python比較頻繁,所幸就用它來(lái)實(shí)現(xiàn)這個(gè)算法,雖然網(wǎng)上有很多代碼,不過(guò)作為一個(gè)學(xué)習(xí)者,還是應(yīng)當(dāng)親自動(dòng)手實(shí)現(xiàn)。2016-11-11
基于Python繪制一個(gè)摸魚(yú)倒計(jì)時(shí)界面
前端時(shí)間推出了一個(gè)摸魚(yú)APP,這篇文章將為大家介紹基于Python繪制一個(gè)摸魚(yú)倒計(jì)時(shí)界面,文中的示例代碼講解詳細(xì),感興趣的可以學(xué)習(xí)一下2021-12-12
使用python實(shí)現(xiàn)3D聚類(lèi)圖示例代碼
這篇文章主要介紹了使用python實(shí)現(xiàn)3D聚類(lèi)圖效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08
python爬取新聞門(mén)戶(hù)網(wǎng)站的示例
短期目前旨在爬取所有新聞門(mén)戶(hù)網(wǎng)站的新聞,每個(gè)門(mén)戶(hù)網(wǎng)站爬蟲(chóng)開(kāi)箱即用,并自動(dòng)保存到同目錄下的 csv/excel 文件中,禁止將所得數(shù)據(jù)商用。2021-04-04
Python腳本操作Excel實(shí)現(xiàn)批量替換功能
這篇文章主要介紹了Python腳本操作Excel實(shí)現(xiàn)批量替換功能,本文使用的是Openpyxl工具,通過(guò)實(shí)例截圖給大家講解的非常詳細(xì),需要的朋友可以參考下2019-11-11

