2013-11-25 3 views
0

제대로 csvDictReader 개체를 반복하는 방법을 이해하는 데 어려움을 겪고 있습니다. 특정 사용자 정의 데이터 코드에 연결된 각 csv 값을 반환하려고합니다. 웹 쿼리에서 사전을 생성하기 때문에 이미 메모리에있는 데이터를 다시 폴링하지 않고 메모리에서 다시 사용하고자합니다.중첩 된 for 루프로 csvDictReader 반복

import sys, csv, urllib2 
class SmfImpl(): 

    def __init__(self, ctx): 
     self.ctx = ctx 
     self.csv_dict = [] 
     self.flag = ['Not Available', ''] 
     self.ticker = 'XOM' 

    def getMorningKey(self, datacode): 
     return fetch_keyratios(self, datacode) 

#these functions are not in the SmfImpl class because they're from a seperate file 
def query_morningstar(self, url_ending): 
     url = 'http://financials.morningstar.com/ajax/exportKR2CSV.html?&callback=?&t=XNYS:%s%s' % (self.ticker, url_ending) 
     req = urllib2.Request(url) 
     response = sniff_query(req) 
     response.readline() 
     return csv.DictReader(response) 

def sniff_query(req): 
    try: 
     response = urllib2.urlopen(req) 
    except urllib2.URLError: 
     return 'Check Connection' 
    sniff = response.readline() 
    if str(sniff) == '': 
     return 'Not Available' 
    return response 

def fetch_keyratios(self, datacode): 
    if datacode < 1 or datacode > 990: 
     return 'Invalid Datacode' 
    #check if we already have the data we need 
    if self.flag[0] == 'Check Connection' or self.flag[0] == 'Not Available' or self.flag[1] != self.ticker: 
     #query remote and check for errors 
     self.csv_dict = query_morningstar(self,'&region=usa&culture=en-US&cur=USD&order=desc') 
     if self.csv_dict == 'Check Connection' or self.csv_dict == 'Not Available': 
      self.flag[1] = '' 
      return self.csv_dict 
     else: 
      self.flag[0] = '' 
      self.flag[1] = self.ticker 
    return sort_keyratios(self, datacode) 

def sort_keyratios(self, datacode):  
    counter = 1 
    skipped = 0 
    skip_lines = [15, 16, 26, 36, 37, 57, 58, 64, 65, 86, 91, 92]    
    #iterate through returned dict line by line 
    for line in self.csv_dict: 
     for item in skip_lines: 
      if counter == item: 
       skipped += 1 
     for val in range(1, len(line)): 
      #match year values to datacodes 
      if datacode == val: 
       return self.csv_dict.fieldnames[val] 
      #match data values to datacodes 
      if datacode-((counter-skipped)*(len(line)-1)) == val: 
       return line[self.csv_dict.fieldnames[val]] 
     counter += 1 
    return 'No Data' 

if __name__ == "__main__": 
    smf = SmfImpl(sys.argv) 
    ticker = 'XOM' 
    for val in range (1,24): 
     print ticker, val,':', smf.getMorningKey(val) 

원래 CSV는 스크립트에 의해 호출됩니다, 그러나 또한

here을 찾을 수 있습니다

내가 갖는 출력은 : 나는 얻기 위해 노력하고 무엇

XOM 1 : TTM 
XOM 2 : 2012-12 
XOM 3 : 2011-12 
XOM 4 : 2010-12 
XOM 5 : 2009-12 
XOM 6 : 2008-12 
XOM 7 : 2007-12 
XOM 8 : 2006-12 
XOM 9 : 2005-12 
XOM 10 : 2004-12 
XOM 11 : 2003-12 
XOM 12 : -35,300 
XOM 13 : 21,899 
XOM 14 : 5.00 
XOM 15 : -3,649 
XOM 16 : None 
XOM 17 : 2008-12 
XOM 18 : 100.00 
XOM 19 : 56.47 
XOM 20 : 42.54 
XOM 21 : 4.65 
XOM 22 : 
XOM 23 : 13.67 

:

XOM 1 : TTM 
XOM 2 : 2012-12 
XOM 3 : 2011-12 
XOM 4 : 2010-12 
XOM 5 : 2009-12 
XOM 6 : 2008-12 
XOM 7 : 2007-12 
XOM 8 : 2006-12 
XOM 9 : 2005-12 
XOM 10 : 2004-12 
XOM 11 : 2003-12 
XOM 12 : 443,708 
XOM 13 : 482,295 
XOM 14 : 486,429 
XOM 15 : 383,221 
XOM 16 : 310,586 
XOM 17 : 477,359 
XOM 18 : 404,552 
XOM 19 : 377,635 
XOM 20 : 370,680 
XOM 21 : 298,035 
XOM 22 : 246,738 
XOM 23 : 27.8 

EDIT : 원본 csv의 줄당 그룹으로 데이터 코드를 매핑하려고합니다. 예 : Years는 1에서 11까지의 데이터 코드 (TTM에서 2003-12), Revenue는 12에서 22 (443708에서 246738)까지의 데이터 코드입니다. 궁극적으로 이러한 데이터 코드는 사용자 입력으로 이동되므로 어떤 순서로든 액세스 할 수 있습니다.

+0

vals/datacode가 항상 오름차순으로 액세스됩니까? csv 전체를 메모리로 읽어 들일 수 있습니까? – martineau

+0

아니요, main에 정의 된 ticker와 val은 궁극적으로 사용자 입력/sys.argv로 이동되므로 임의의 순서로 값에 액세스 할 수 있습니다. – dman

+0

글쎄, 한 가지는,'csv.DictReader'가 순차적 인 매너의 데이터에 접근하기 때문에 매번 csv 데이터의 적어도 일부분을 다시 읽는 것을 의미 할 것입니다. 그래서 나는 모든 것을 메모리로 읽어 들일 것을 제안했습니다. 랜덤 억세스를 허용 할 것이다. 또한 귀하의 질문에 추가 정보가 추가되어야합니다. 왜냐하면 코드와 코드에서 주석이 충분히 명확하지 않기 때문에 csv 파일의 위치에 대한 데이터 코드 매핑을 설명하는 추가 정보가 필요합니다. 솔직히 말해서 왜 당신이'csv.DictReader'를 사용하여 이것을하고 있는지 분명하지 않습니다. – martineau

답변

1

다음은 어떻게 수행할까요? 원하는 출력을 생성합니다. 나는 코드를 여기에 stackoverflow에 코드 상자에 더 잘 맞게 약간의 코드를 다시 포맷했습니다. 까다로운 부분은 datacode에서 row, column까지의 데이터를 메모리의 매트릭스로 읽어 들인 것을 알아내는 것이 었습니다. 당신이 정말로 열/필드 이름의 사용을하지 않은 이후

import sys, csv, urllib2 
class SmfImpl(): 
    def __init__(self, ctx): 
     self.ctx = ctx 
     self.csv_reader = '' 
     self.flag = ['Not Available', ''] 
     self.ticker = 'XOM' 

    def getMorningKey(self, datacode): 
     return fetch_keyratios(self, datacode) 

#these functions are not in the SmfImpl class because they're in a seperate file 
def query_morningstar(self, url_ending): 
    MORNING_STAR = 'http://financials.morningstar.com/ajax/exportKR2CSV.html' 
    url = MORNING_STAR + '?&callback=?&t=XNYS:%s%s' % (self.ticker, url_ending) 
    req = urllib2.Request(url) 
    response = sniff_query(req) 
    response.readline() 
    return csv.reader(response) 

def sniff_query(req): 
    try: 
     response = urllib2.urlopen(req) 
    except urllib2.URLError: 
     return 'Check Connection' 
    sniff = response.readline() 
    if str(sniff) == '': 
     return 'Not Available' 
    return response 

def fetch_keyratios(self, datacode): 
    if datacode < 1 or datacode > 990: 
     return 'Invalid Datacode' 
    #check if we already have the data we need 
    if(self.flag[0] == 'Check Connection' or 
     self.flag[0] == 'Not Available' or self.flag[1] != self.ticker): 
     #query remote and check for errors 
     self.csv_reader = query_morningstar(self, 
           '&region=usa&culture=en-US&cur=USD&order=desc') 
     if(self.csv_reader == 'Check Connection' or 
      self.csv_reader == 'Not Available'): 
      self.flag[1] = '' 
      return self.csv_reader # actually response status message 
     else: 
      self.flag[0] = '' 
      self.flag[1] = self.ticker 
      # read entire dataset in memory skipping lines as neccessary 
      self.data = [row[1:] for row in self.csv_reader if len(row) == 12] 

    return sort_keyratios(self, datacode) 

def sort_keyratios(self, datacode): 
    # convert datacode to row, column and return data in that position of list 
    row, col = divmod(datacode-1, 11) 
    return self.data[row][col] 

if __name__ == "__main__": 
    smf = SmfImpl(sys.argv) 
    ticker = 'XOM' 
    for val in range(1, 24): 
     print ticker, val,':', smf.getMorningKey(val) 

csv.reader()

는 대신 csv.DictReader 사용됩니다. 응답의 모든 데이터 (처음 몇 줄 제외)는 처음 사용시 getMorningKey()이 호출 될 때 목록을 사용하여 읽혀집니다. 이 방법으로 읽은 각 행은 건너 뛰지 않은 12 개 항목의 목록이어야합니다. 또한 마지막 11 개 항목 만 저장되므로 데이터 코드에서 쉽게 매핑 할 수 있습니다. 결과는 행이 행 번호이고 열이 필드 x 호인 2 차원 행렬입니다. Exxon 예제 시세 표시기에 대한 원시 행렬 데이터보기가이 web page에 표시됩니다.

이 방법을 사용하면 논리가 매우 단순 해지고 모든 데이터가 메모리에 저장되므로 이후 호출에서 다시 사용되어 쿼리를 다시 수행하지 않고도 임의 액세스가 가능해집니다.

XOM 1 : TTM 
XOM 2 : 2012-12 
XOM 3 : 2011-12 
XOM 4 : 2010-12 
XOM 5 : 2009-12 
XOM 6 : 2008-12 
XOM 7 : 2007-12 
XOM 8 : 2006-12 
XOM 9 : 2005-12 
XOM 10 : 2004-12 
XOM 11 : 2003-12 
XOM 12 : 443,708 
XOM 13 : 482,295 
XOM 14 : 486,429 
XOM 15 : 383,221 
XOM 16 : 310,586 
XOM 17 : 477,359 
XOM 18 : 404,552 
XOM 19 : 377,635 
XOM 20 : 370,680 
XOM 21 : 298,035 
XOM 22 : 246,738 
XOM 23 : 27.8 
+0

이것은 올바른 길로 나를 잡았습니다. 진심으로 감사드립니다. 나는 다른 사람들에게 도움이 될 수 있기 때문에 내가 찾고있는 기능을 완성한 답을 올렸다. – dman

0

마티가 올바른지 게시 대답 :

여기에 출력합니다. 마무리 및 얻으려면 내가 원래 내가 찾던 기능은 다음과 sort_keyratios 변경 :

def sort_keyratios:  
    #define rows that have no useful data 
    skip_list = [16,17,18,28,29,38,39,40,41,46,51,56,61,62,63,69,70,71,92,93,98,99,100] 
    skipped = 0 
    # match datacode to row, column and return data in that position of list 
    for row in range(0,109): 
     if row in skip_list: 
      skipped+=11 
      continue 
     for col in range(0,12): 
      if datacode == col+(11*row)-skipped: 
       return self.data[row][col] 
1

이것은 당신이 당신의 자신의 질문에 게시 된 질문에 대해 답 sort_keyratios()에 수행 된 변경에 응답하는 것입니다. 또한 추가 정보가 유용하다는 사실을 알았 으면 다른 사람에게 투표하는 것이 좋습니다. 어쨌든 < 힌트 >

, 당신이 수행되고 무엇을 할 수 훨씬보다 효율적으로 단지의 값을 조회하려면이 이전에 내장 된 테이블을 사용하여 다음 번 (row, col) 쌍의 각 datacode 매핑하는 사전을 구축하고,에 의해 기능. 이를 위해 create_datacode_map()이라는 새 기능을 추가했습니다.여기

그것이 사용될 수있는 방법은 다음과 같습니다

def create_datacode_map(): 
    """ Create dictionary mapping datacodes to (row, col) in data. """ 
    # define rows that have no useful data 
    skip_list = {16, 17, 18, 28, 29, 38, 39, 40, 41, 46, 51, 56, 61, 62, 63, 69, 
       70, 71, 92, 93, 98, 99, 100} 
    def find_row_col(datacode): 
     skipped = 0 
     # match datacode to row, column 
     for row in xrange(0, 109): 
      if row in skip_list: 
       skipped += 11 
       continue 
      for col in xrange(0, 12): 
       if datacode == col + (11*row) - skipped: 
        return row, col 

    # create and return the dictionary 
    return {datacode: find_row_col(datacode) for datacode in xrange(1, 910)} 

def sort_keyratios(self, datacode): 
    # convert datacode to row, column and return data in that position of list 
    if not hasattr(self, 'datacode_map'): 
     self.datacode_map = create_datacode_map() 
    row, col = self.datacode_map[datacode] # lookup conversion 
    return self.data[row][col] 

self.datacode_map 존재하지 않는 경우는 그에게 전화를 생성 될 때마다의 존재 sort_keyratios() 표시 검사의 버전입니다. 이미 fetch_keyratios(()에있는 것이 더 효율적이므로 sort_keyratios()이 있다고 가정하고 호출 할 때마다 확인하지 않아도됩니다.

+0

dict에 완전한 동그라미 매핑을 되 찾는 느낌이 들었습니다. 나는 당신이 내가 파이썬을 어려운 길을 배우고 있다고 추론했다고 확신한다. 파이썬 3의 자비에 자신을 발견 할 수도 있지만 내 자신의 학습을 안내하는 데 도움이되는 설명과 미묘함에 감사드립니다 (예 :'xrange()''range()').)'). 'find_row_col()'을'create_datacode_map()'에 두지 않고 하위 함수로 만드는 이유는 무엇입니까? – dman

+0

예, 아직 다른 사전이지만 목적은 완전히 다릅니다. 파이썬에는 버전 2에서 3으로 변환 할 도구가 있는데, xrange를 사용하는 문제를 해결할 것이므로 그 이유 때문에 피하지 않을 것입니다. 'find_row_col()'은'create_datacode_map()'에 의해서만 호출되기 때문에 중첩 된 함수로 만들었고'skip_list'는 호출 될 때마다 함수 자체의 외부에서 생성 될 수 있습니다. – martineau