Oli*_*ver 5 python csv processing text
我有这个任务,我一直在努力,但我对我的方法有极度的疑虑.
所以问题是我有大量奇怪的格式化(并且不一致)的excel文件,我需要为每个条目提取某些字段.示例数据集是

我最初的方法是这样的:
我遇到的问题是格式(看似组织良好)几乎是随机文件.每行包含相同的字段,但顺序,间距和措辞不同.我编写了一个脚本来正确处理一个文件,但它不适用于任何其他文件.
所以我的问题是,是否有更强大的方法来处理这个问题,而不是简单的字符串处理?我想到的是更多的模糊逻辑方法,试图固定一个项目的哪个字段,这可以处理输入有点任意.你会如何解决这个问题?
如果它有助于解决问题,这里是我写的脚本:
# This file takes a tax CSV file as input
# and separates it into counties
# then appends each county's entries onto
# the end of the master out.csv
# which will contain everything including
# taxes, bonds, etc from all years
#import the data csv
import sys
import re
import csv
def cleancommas(x):
toggle=False
for i,j in enumerate(x):
if j=="\"":
toggle=not toggle
if toggle==True:
if j==",":
x=x[:i]+" "+x[i+1:]
return x
def districtatize(x):
#list indexes of entries starting with "for" or "to" of length >5
indices=[1]
for i,j in enumerate(x):
if len(j)>2:
if j[:2]=="to":
indices.append(i)
if len(j)>3:
if j[:3]==" to" or j[:3]=="for":
indices.append(i)
if len(j)>5:
if j[:5]==" \"for" or j[:5]==" \'for":
indices.append(i)
if len(j)>4:
if j[:4]==" \"to" or j[:4]==" \'to" or j[:4]==" for":
indices.append(i)
if len(indices)==1:
return [x[0],x[1:len(x)-1]]
new=[x[0],x[1:indices[1]+1]]
z=1
while z<len(indices)-1:
new.append(x[indices[z]+1:indices[z+1]+1])
z+=1
return new
#should return a list of lists. First entry will be county
#each successive element in list will be list by district
def splitforstos(string):
for itemind,item in enumerate(string): # take all exception cases that didn't get processed
splitfor=re.split('(?<=\d)\s\s(?=for)',item) # correctly and split them up so that the for begins
splitto=re.split('(?<=\d)\s\s(?=to)',item) # a cell
if len(splitfor)>1:
print "\n\n\nfor detected\n\n"
string.remove(item)
string.insert(itemind,splitfor[0])
string.insert(itemind+1,splitfor[1])
elif len(splitto)>1:
print "\n\n\nto detected\n\n"
string.remove(item)
string.insert(itemind,splitto[0])
string.insert(itemind+1,splitto[1])
def analyze(x):
#input should be a string of content
#target values are nomills,levytype,term,yearcom,yeardue
clean=cleancommas(x)
countylist=clean.split(',')
emptystrip=filter(lambda a: a != '',countylist)
empt2strip=filter(lambda a: a != ' ', emptystrip)
singstrip=filter(lambda a: a != '\' \'',empt2strip)
quotestrip=filter(lambda a: a !='\" \"',singstrip)
splitforstos(quotestrip)
distd=districtatize(quotestrip)
print '\n\ndistrictized\n\n',distd
county = distd[0]
for x in distd[1:]:
if len(x)>8:
district=x[0]
vote1=x[1]
votemil=x[2]
spaceindex=[m.start() for m in re.finditer(' ', votemil)][-1]
vote2=votemil[:spaceindex]
mills=votemil[spaceindex+1:]
votetype=x[4]
numyears=x[6]
yearcom=x[8]
yeardue=x[10]
reason=x[11]
data = [filename,county,district, vote1, vote2, mills, votetype, numyears, yearcom, yeardue, reason]
print "data",data
else:
print "x\n\n",x
district=x[0]
vote1=x[1]
votemil=x[2]
spaceindex=[m.start() for m in re.finditer(' ', votemil)][-1]
vote2=votemil[:spaceindex]
mills=votemil[spaceindex+1:]
votetype=x[4]
special=x[5]
splitspec=special.split(' ')
try:
forind=[i for i,j in enumerate(splitspec) if j=='for'][0]
numyears=splitspec[forind+1]
yearcom=splitspec[forind+6]
except:
forind=[i for i,j in enumerate(splitspec) if j=='commencing'][0]
numyears=None
yearcom=splitspec[forind+2]
yeardue=str(x[6])[-4:]
reason=x[7]
data = [filename,county,district,vote1,vote2,mills,votetype,numyears,yearcom,yeardue,reason]
print "data other", data
openfile=csv.writer(open('out.csv','a'),delimiter=',', quotechar='|',quoting=csv.QUOTE_MINIMAL)
openfile.writerow(data)
# call the file like so: python tax.py 2007May8Tax.csv
filename = sys.argv[1] #the file is the first argument
f=open(filename,'r')
contents=f.read() #entire csv as string
#find index of every instance of the word county
separators=[m.start() for m in re.finditer('\w+\sCOUNTY',contents)] #alternative implementation in regex
# split contents into sections by county
# analyze each section and append to out.csv
for x,y in enumerate(separators):
try:
data = contents[y:separators[x+1]]
except:
data = contents[y:]
analyze(data)
Run Code Online (Sandbox Code Playgroud)
有没有比简单的字符串处理更强大的方法来解决这个问题?
并不真地。
我想到的更多的是一种模糊逻辑方法,用于尝试确定某个项目属于哪个字段,它可以处理有点任意的输入。您将如何解决这个问题?
经过大量的分析和编程后,它不会比您所拥有的好得多。
不幸的是,阅读人们准备的东西需要像人一样的大脑。
您可以混用 NLTK 来尝试做得更好,但效果也不是很好。
您不需要全新的方法。您需要简化您的方法。
例如。
district=x[0]
vote1=x[1]
votemil=x[2]
spaceindex=[m.start() for m in re.finditer(' ', votemil)][-1]
vote2=votemil[:spaceindex]
mills=votemil[spaceindex+1:]
votetype=x[4]
numyears=x[6]
yearcom=x[8]
yeardue=x[10]
reason=x[11]
data = [filename,county,district, vote1, vote2, mills, votetype, numyears, yearcom, yeardue, reason]
print "data",data
Run Code Online (Sandbox Code Playgroud)
可以通过使用命名元组来改进。
然后构建类似这样的东西。
data = SomeSensibleName(
district= x[0],
vote1=x[1], ... etc.
)
Run Code Online (Sandbox Code Playgroud)
这样您就不会创建大量中间(且基本上无信息)松散变量。
另外,继续查看您的analyze函数(以及任何其他函数)以找出各种“模式匹配”规则。这个想法是,您将检查一个县的数据,逐步执行一系列函数,直到其中一个与模式匹配;这也将创建命名元组。你想要这样的东西。
for p in ( some, list, of, functions ):
match= p(data)
if match:
return match
Run Code Online (Sandbox Code Playgroud)
每个函数要么返回一个命名元组(因为它喜欢该行),要么返回一个命名元组None(因为它不喜欢该行)。
| 归档时间: |
|
| 查看次数: |
585 次 |
| 最近记录: |