[英]Python - Extract and reformat field names from rows of data
我有一個平面文本文件(infile),我想重組。 它有一些制表符分隔的列,看起來像這樣:
Person1 HEIGHT=60;WEIGHT=100;AGE=22
Person2 HEIGHT=62;WEIGHT=101;AGE=25
Person3 HEIGHT=64;WEIGHT=110;AGE=29
我希望它看起來像這樣:
PERSON HEIGHT WEIGHT AGE
1 60 100 22
2 62 101 25
3 64 110 29
您可以看到第二列實際上包含幾個以分號分隔的標題/值字段,我想將它們重組為典型的列標題行。
現在我有:
for line in infile:
line = line.split("\t")
line_meta = line[1].split(";")
print line_meta
我認為最好的解決方案現在將循環遍歷line_meta變量,使用正則表達式來檢測標題名稱(檢測以多個大寫字母開頭並以“=”_結尾的字符串),將每個標題添加到字典作為鍵,然后將其余字符串存儲為值。 然后,對於下一行,如果檢測到相同的標題,則只附加到現有字典。
任何人都可以幫助這個代碼或有關如何繼續的提示反饋?
謝謝
編輯:謝謝你的回復。 我為這個例子簡化了我的數據,但是這里有一個實際的meta列是什么樣的(仍然是分隔的,但值類型是混合的):
P=0.9626;IPU=.$.+1T.+1T.+;IRF=ncRNA;IUC=UTR3;IGN=NCRNA00115;IGI=NCRNA00115,RP11-206L10.16-001;IET=0;IEO=0;IEN=.;IHT=0;IHVC=0;IHD=.;IHI=.;IHN=.;IDI=.;IDN=.;ITMAF=.;ITAMR=.;ITASN=.;ITAFR=.;ITEUR=.;ITNRB=+A;ISF=.;ISD=.;ISM=.;ISX=.;
您可以使用一個正則表達式來拆分key = value對:
import re
key_value = re.compile('(?P<key>[A-Z]+)=(?P<value>\[^\s=;]+)(?:(?=;)|$)')
此表達式使用命名組,但如果您發現它更容易閱讀,則可以不使用這些組:
key_value = re.compile('([A-Z]+)=([^\s=;])(?:(?=;)|$)')
(?:..)
組是非捕獲組; 它只用於標記|
或符號適用於。 該模式匹配=
符號前的大寫字符,以及不是空格的任何內容,a =
或;
性格,只要有一個;
或者在值之后的字符串的結尾。
這會拆分每行的鍵和值:
>>> key_value = re.compile('(?P<key>[A-Z]+)=(?P<value>[^\s=;]+)(?:(?=;)|$)')
>>> key_value.findall('Person1\tHEIGHT=60;WEIGHT=100;AGE=22')
[('HEIGHT', '60'), ('WEIGHT', '100'), ('AGE', '22')]
這很容易變成字典:
>>> dict(key_value.findall('Person1\tHEIGHT=60;WEIGHT=100;AGE=22'))
{'AGE': '22', 'WEIGHT': '100', 'HEIGHT': '60'}
然后,您可以使用csv.DictWriter()
編寫這些內容:
import csv
import re
key_value = re.compile('(?P<key>[A-Z]+)=(?P<value>[^\s=;]+)(?:(?=;)|$)')
with open(inputfilename) as infile, open(outputfilename, 'wb') as outfile:
writer = csv.DictWriter(outfile, ('PERSON', 'HEIGHT', 'WEIGHT', 'AGE'), delimiter='\t')
writer.writeheader()
for line in infile:
person = line.split('\t', 1)[0]
row = dict(key_value.findall(line))
row['PERSON'] = person
writer.writerow(row)
基於您的真實數據樣本的演示:
>>> dict(key_value.findall(' P=0.9626;IPU=.$.+1T.+1T.+;IRF=ncRNA;IUC=UTR3;IGN=NCRNA00115;IGI=NCRNA00115,RP11-206L10.16-001;IET=0;IEO=0;IEN=.;IHT=0;IHVC=0;IHD=.;IHI=.;IHN=.;IDI=.;IDN=.;ITMAF=.;ITAMR=.;ITASN=.;ITAFR=.;ITEUR=.;ITNRB=+A;ISF=.;ISD=.;ISM=.;ISX=.;\n'))
{'ISX': '.', 'ITAMR': '.', 'IDN': '.', 'ISM': '.', 'IDI': '.', 'ISF': '.', 'ISD': '.', 'ITMAF': '.', 'IUC': 'UTR3', 'IGI': 'NCRNA00115,RP11-206L10.16-001', 'ITNRB': '+A', 'IHVC': '0', 'IET': '0', 'ITASN': '.', 'ITEUR': '.', 'ITAFR': '.', 'IEO': '0', 'IEN': '.', 'IGN': 'NCRNA00115', 'IRF': 'ncRNA', 'P': '0.9626', 'IHT': '0', 'IHI': '.', 'IHN': '.', 'IPU': '.$.+1T.+1T.+', 'IHD': '.'}
你可以試試這個
data = open('testfile.dat').read().split('\n')
def newcmp(x,y):
rv = cmp(len(x[1]), len(y[1]))
if rv: return rv
else: return cmp(x[0], y[0]) # alphabetical
persons = {}
attributes = {}
nAttrs = 0
for l in data:
pname , pvals = line.split('\t')[:2]
for atName, atVal in (x.split('=') for x in pvals.psplit(';'))
try:
persons[pName][attributes[atName]] = atVal
except KeyError:
attributes[aName] = nAttrs
persons[pName][attributes[atName]] = atVal
nAttr += 1
headers = ['NAME'] + range(nAttrs)
for x in attributes.keys(): headers[attributes[x]+1] = x
values = []
for pName, pVals in sorted(persons.items(), cmp=newcmp)
if len(pVals) < nAttrs: pVals += [0 for x in xrange(nAttrs - len(pVals))]
values.append('\t'.join(('%d'%x for x in pVals)))
outfh = open('outputfile.dat', 'w')
outfh.write('%s\n%s\n'%('\t'.join(headers), '\n'.join(values)))
outfh.close()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.