2012-01-23 19 views
5

Tôi có nhiệm vụ này mà tôi đã làm việc, nhưng có những hiểu lầm cực đoan về phương pháp của tôi.Phân tích dữ liệu để định dạng chuỗi không nhất quán

Vì vậy, vấn đề là tôi có rất nhiều tệp excel được định dạng lạ (và không nhất quán) và tôi cần trích xuất một số trường nhất định cho mỗi mục nhập. Một bộ dữ liệu ví dụ là

a look at the data

cách tiếp cận ban đầu của tôi là thế này:

  1. Xuất khẩu sang csv
  2. riêng biệt vào các quận
  3. riêng vào huyện
  4. Phân tích mỗi huyện riêng, kéo các giá trị ngoài số
  5. ghi vào output.csv

Vấn đề tôi gặp phải là định dạng (dường như được tổ chức tốt) gần như ngẫu nhiên trên các tệp. Mỗi dòng chứa các trường giống nhau, nhưng theo thứ tự, khoảng cách và từ ngữ khác nhau. Tôi đã viết một kịch bản để xử lý chính xác một tệp, nhưng nó không hoạt động trên bất kỳ tệp nào khác.

Câu hỏi của tôi là, có phương pháp tiếp cận vấn đề này mạnh mẽ hơn là xử lý chuỗi đơn giản không? Những gì tôi đã có trong tâm trí là nhiều hơn một cách tiếp cận logic mờ cho cố gắng để pin mà lĩnh vực một mục được, mà có thể xử lý các yếu tố đầu vào là một chút tùy ý. Bạn sẽ tiếp cận vấn đề này như thế nào?

Nếu nó giúp sáng tỏ vấn đề, đây là kịch bản tôi đã viết:

# 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) 
+7

Cách tốt nhất và đáng tin cậy nhất để giải quyết vấn đề này là buộc mọi người cung cấp cho bạn dữ liệu này tuân theo định dạng chuẩn, nhưng tôi không biết đó có phải là tùy chọn có sẵn cho bạn hay không. Nếu không thi hành một số cấu trúc, những người cung cấp dữ liệu này sẽ liên tục phá vỡ chương trình của bạn. –

Trả lời

3

đang có một phương pháp mạnh mẽ hơn để tiếp cận vấn đề này chứ không phải xử lý chuỗi đơn giản?

Không thực sự.

Điều tôi đã nghĩ là có nhiều cách tiếp cận logic mờ hơn khi cố gắng ghim trường nào một mục, có thể xử lý các đầu vào tùy ý một chút. Bạn sẽ tiếp cận vấn đề này như thế nào?

Sau một tấn phân tích và lập trình, nó sẽ không tốt hơn đáng kể so với những gì bạn có.

Công cụ đọc được mọi người chuẩn bị yêu cầu - thật đáng buồn - bộ não giống người.

Bạn có thể gây rối với NLTK để thử và làm một công việc tốt hơn, nhưng nó cũng không hoạt động tốt.

Bạn không cần một cách tiếp cận hoàn toàn mới. Bạn cần sắp xếp hợp lý phương pháp tiếp cận mà bạn có.

Ví dụ:

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 

Có thể được cải thiện bằng cách sử dụng bộ tên có tên.

Sau đó, tạo một cái gì đó như thế này.

data = SomeSensibleName( 
    district= x[0], 
    vote1=x[1], ... etc. 
) 

Vì vậy, bạn không tạo ra nhiều biến số trung gian (và phần lớn không rõ ràng).

Ngoài ra, hãy tiếp tục xem chức năng analyze của bạn (và bất kỳ chức năng nào khác) để rút ra các quy tắc "khớp mẫu" khác nhau. Ý tưởng là bạn sẽ kiểm tra dữ liệu của một hạt, bước qua một loạt các chức năng cho đến khi một phù hợp với mô hình; điều này cũng sẽ tạo ra tuple có tên. Bạn muốn một cái gì đó như thế này.

for p in (some, list, of, functions): 
    match= p(data) 
    if match: 
     return match 

Mỗi hàm trả về một bộ tên có tên (vì nó thích hàng) hoặc None (vì nó không thích hàng).