2017-02-23 1 views
-1

저는 Python을 처음 접했고 메모리 오류를 피하기 위해이 프로그램을 최적화하는 방법을 알고 있습니다.메모리 오류를 피하기 위해 데이터 변환 프로그램을 최적화하십시오.

두 개의 통합 문서 (raw_data 및 매핑)에서 데이터를 읽으려고합니다. 데이터를 변환하는 매핑 문서를 사용하여 raw_data를 새 스프레드 시트로 변환하려고합니다. 따라서 통합 문서를로드하고 매핑 데이터에서 데이터 사전을 만들고 변환을 시작합니다. 그러나 메모리 오류가 발생합니다.

이 오류를 피하기 위해 아래 코드를 최적화 할 수있는 방법이 있습니까?

import openpyxl 
from openpyxl.utils import get_column_letter 

mapping = openpyxl.load_workbook(r'C:...\mapping.xlsx') #load mapping doc 
wb = openpyxl.load_workbook(r'C:...\raw_data.xlsx') #load raw data 


sheet = wb.active #look at the active sheet in the raw data file 
user_map_raw = mapping.get_sheet_by_name('User ID Mapping') #for user ids 
item_map_raw = mapping.get_sheet_by_name('Item ID Mapping') #for item ids 
...other mappings here 

def load(sheet): 

    user_dict = {} 
    print "creating user dictionary..." 
    for row in range(1, user_map_raw.max_row+1): 
     old_name = user_map_raw['A' + str(row)].value #old user name 
     new_name = user_map_raw['B' + str(row)].value #new user name 
     user_dict[old_name] = new_name #old name is key for the new name 

    item_dict = {} 
    print "creating item id dictionary..." 
    for row in range(1, item_map_raw.max_row+1): 
     old_item = item_map_raw['A' + str(row)].value #old item id 
     new_item = item_map_raw['B' + str(row)].value #new item id 
     item_dict[old_item] = new_item #old item id is key for new item id 

    raw = [] #empty list to store data before writing to new file 
    for row in range(2, sheet.max_row+1): #loop thru raw data and map 
     print "loading row %s" % row 
     user_ID = user_dict[sheet['A' + str(row)].value] 
     item_type = sheet['B' + str(row)].value 
     item_ID = item_dict[sheet['C' + str(row)].value] 
     ...other transformations here 
     add = [user_ID, item_type, item_ID, ...] 
     raw.append(add) #add transformed data to list 

    new = openpyxl.Workbook() #create new workbook 
    output = new.active #select the active sheet 
    for i in range(len(raw)): #loop through transformed data list 
     "print writing row %s" %i 
     for j in range(len(raw[i])): #write to new sheet 
      output[get_column_letter(j+1) + str(i+1)] = raw[i][j] 
    new.save('new_doc.xlsx') 

load(sheet) 

답변

1

기본 최적화는 작성하기 전에 전체 결과를 메모리에 저장하는 것을 피하고 메모리에 전체 기본 통합 문서를로드하지 않는 것입니다. 기능을 축소하고 반복자를 지원하여 최적화 된 표현을 구현하여 런타임에 많은 메모리를 절약 할 수있는 및 read_only 모드 for openpyxl 통합 문서가 있습니다. 편집하는 대신 새 파일을 쓰고 있으므로이 모드는 큰 차이를 만들 수 있습니다.

wb = openpyxl.load_workbook(r'C:...\raw_data.xlsx', read_only=True) 
sheet = wb.active 

# mapping related code... 

from openpyxl.writer.write_only import WriteOnlyCell 
wb = openpyxl.Workbook(write_only=True) #create new workbook 
ws = new.create_sheet() 

for row in sheet.iter_rows(row_offset=1): 
    for i, cell in enumerate(row): 
     if i = 0: #A 
      user_ID = WriteOnlyCell(ws, user_dict[cell.value]) 
     elif i = 1: #B 
      item_type = WriteOnlyCell(ws, cell.value) 
     elif i = 2: #C 
      item_ID = WriteOnlyCell(ws, item_dict[cell.value]) 
     else: 
      break 
    ws.append([user_ID, item_type, item_ID]) 

wb.save('new_doc.xlsx') 

발전기이므로 아래 첨자를 사용할 수 없으므로 셀을 반복해야합니다. clunky,하지만 나는 피곤해 보인다.

작은 절약을 위해 Python 2.x를 사용하는 경우 range 함수를 사용할 때마다 매우 큰 스프레드 시트가있는 경우 목록이 귀하의 범위만큼 큰 메모리에 만들어지고 램. 귀하의 경우에는 아마도 일부 메모리를 절약하기 위해 각 반복을 동적으로 생성하는 xrange을 사용할 수 있습니다.

+0

안녕하세요, 고마워요. 내 유일한 질문 : 왜 row_offset = 2를 사용 했습니까? – kbball

+0

질문 예제에서 몇 줄을 건너 뛰고 2 열에서 시작하는 메인 시트를 반복합니다 :'range (2, sheet.max_row + 1) :'. 바라 건데'row_offset'도 같은 일을합니다. openpyxl 문서에서 알기 힘듭니다. 원하는 행이 모두 있는지 확인해야합니다. – systemjack

+0

맞아, 나는 그것이 row_offset = 1이어야한다고 생각한다. 그러나 어쨋든 어쨌든 지금 일하고있다. 이 모든 노력에 감사드립니다. 주요 고려 사항 : 파일을 읽기 전용으로 읽고 쓰기 전용으로 쓴다. iter_rows를 사용하여 셀 값 추출 – kbball

0

소스 파일을 읽을 때 read-only 모드를 사용하고 결과를 쓰려면 write-only 모드를 사용할 수 있습니다. 이렇게하면 메모리 사용을 최소화 할 수 있습니다.

관련 문제