lecture4.py


# -*- coding:utf-8 -*-
# Python lecture 4
# keeHwan Nam, Dept. of physics, KAIST, 2013.

# 실험 데이터 파일 처리하기 실전 테크닉 - 기초, 반복작업, 결과물 다듬기, 소소한 팁

# 실제로 실험을 하게 되면, 적게는 수십개에서 많게는 수만개의 데이터 파일이 쌓이게 된다. 이 파일들을 어떻게 자동으로 처리할 수 있는지 알아보자.

# 실험 데이터 처리에서 가장 중요한 것은 파일을 일단 자동으로 읽어오는 것이다.

# 어쨌든, 일단 다음의 모듈을 불러오는 것이 가장 첫 단계이다.

import os
import os.path

# 이 모듈들은 파이썬에서 '파일의 경로명'을 다룰 수 있도록 한다. 경로명이란 실제로 파일이 어디에 있는지 말해주는 주소 같은 것이다.

# 경로명이 다음과 같이 주어졌다고 치자.

mypath = 'c:\\data'

# \기호를 두개 넣은건 나중에 괴이한 일이 벌어지지 않도록 하기 위하여 미리 손을 써둔 것이다. 경로명에 있는 \를 모두 \\로 바꿔두지 않으면, 틀린데가 없어 보이는데 실행이 안되는 일이 벌어질 수 있다. 왜 그런지는 python escape characters 에 대해서 알아보면 된다.

# 그럼 이제 우리에게는 저 디렉토리 안에 있는 파일들의 목록이 필요하다.

myfiles = os.listdir(pymath)

# os.listdir()이라는 함수가 그 일을 해준다. 이제 myfiles라는 '리스느'가 생겼으므로 다음과 같이 써서 일을 할 수 있다.

for mf in myfiles:
    fileProcess(mf)

# 하지만 문제는 이것만으로는 충분하지 않다는 것이다. 왜냐하면 os.listdir() 함수는 경로명을 뺀, 순수한 그 '이름'들의 목록만을 알려주기 때문이다. 우리가 파일을 열기 위해서는 경로명+파일명이 필요하므로, 실제로는 다음과 같이 처리해야 한다.

for mf in myfile:
    fileProcess(mypath+"\\"+mf)

# 이제 fileProcess()라는 함수를 만들어서, 파일 하나하나를 어떻게 처리할지 생각해 보자.

# 데이터 파일은 텍스트 파일 아니면 바이너리 파일로 저장된다. 일단 바이너리는 쓰기 힘드니까 텍스트 파일을 처리하는 것 부터 해본다.

# 데이터 파일에 실제로 다음과 같이 기록되어 있다고 하자.

'''
-1.9e-06     7.97e-07     -8.5783931549247703e-10     -9.7362985182677175e-10     -1.3762538408048596e-10     9.9564622537186427e-11
-1.9e-06     8.46e-07     -7.4824717605474142e-10     -9.1441781733662261e-10     -1.2837483027640561e-10     8.8900007035819333e-11
-1.9e-06     8.96e-07     -6.4783294293579292e-10     -8.5092345806972556e-10     -1.1860950379225859e-10     7.8859478980600898e-11
-1.9e-06     9.46e-07     -5.5678785177338635e-10     -7.8505574393254601e-10     -1.0861474129660382e-10     6.9501614214156576e-11
-1.9e-06     9.96e-07     -4.7504242597008922e-10     -7.1847384904530101e-10     -9.8635766382808557e-11     6.0863824434377259e-11
-1.9e-06     1.04e-06     -4.0238736681761767e-10     -6.5259129272929548e-10     -8.8875171315561072e-11     5.2964091511969546e-11
-1.9e-06     1.09e-06     -3.3836132632978519e-10     -5.8856342378430333e-10     -7.9493842491901663e-11     4.5803169315989476e-11
-1.9e-06     1.16e-06     -2.8244751702740876e-10     -5.2729175071217892e-10     -7.0613168120409343e-11     3.9367080075227634e-11
'''

# 위의 파일은 숫자로 되어 있고, 중간에 빈칸이 있으며, 한줄이 하나의 데이터를 나타낸다. 그럼, 파이썬에서 저걸 다루려면 리스트로 해보는 것이 가장 간편할 것이다.

# 그럼 일단 fileProcess() 함수를 정의하자.

def fileProcess(fn):
    mydata = open(fn, 'r') # 이렇게 하면 파일을 읽기 전용 모드로 열어서 mydata라고 부르기로 한 것이다.
    for i in range(datafile_Length):
        data1=dataProcess(mydata.readline())

# 여기서 dataProcess()는 fileProcess()보다 앞부분에서 정의(def) 되어 있어야 한다. 지금은 설명을 위해서 뒤에 배치했을 뿐이다.

# mydata.readline()은 mydata에 있는 파일에서 1줄을 읽어오라는 뜻이다.

# dataProcess()는 나중에 정의한다 치고, 일단 위의 코드를 잘 보자. for 구문으로 돌리는데, datafile_Length만큼 돌리게 되어 있다. datafile_length는 데이터 파일의 길이이다. 즉, 데이터 파일이 몇줄인지 알고 있을 때 그 수를 여기에 집어넣어주면 된다. 하지만 대부분의 경우 데이터 파일의 길이는 계속 변하고, 변하지 않더라도 신경쓰고 싶지 않을 것이다. 그런 경우에 다음과 같은 방법을 사용할 수 있다.

import numpy
def fileProcess(fn):
    mydata = open(fn, 'r')
    while True:
        data1=mydata.readline()
        tmp = numpy.array(eval("["+data1.replace("\t",",")+"]"))
        if len(tmp)==0:
            break
        data1=dataProcess(tmp)

# 위와 같이 while 구문을 이용해서 반복시키면, 조건에 True가 들어가 있으므로 무한 반복된다. 즉, 파일의 길이와 상관 없이 무한히 파일 처리 과정이 계속된다는 뜻이다. 물론 모든 데이터 파일은 길이가 정해져 있고, 유한하기 때문에 실제로 그런 일이 일어나서는 안될 것이다.

# 그래서 그 뒤에 if 구문을 이용해서, 읽어온 데이터가 없으면 break를 써서 while 루프를 벗어나도록 하고 있다. 읽어온 데이터가 없는 경우엔 dataProcess()함수가 실행되지 않고 그대로 while 루프를 빠져나가 버릴 것이다. 그럼 그 앞에서 tmp에 무슨 짓을 한 것일까?

# tmp에는 numpy.array를 집어넣었다. 그럼 그 안에서는 eval이 있고 replace()가 보일 것이다.

# data1.replace()는 data1에 있는 내용을 고친다. replace("\t", ",")함수가 하는 일은 내용중에서 \t를 찾아서 ,으로 바꿔주는 일이다. 여기서 \t나 ,는 원하는대로 다른 기호나 문자열로 바꿀 수 있다. 1글자뿐만 아니라 여러 글자도 된다.

# \t가 보이지 않는다는 사람이 있을 수 있는데, 그런 사람은 아마 python escape characters가 뭔지 찾아보지 않은 사람일 것이라고 생각한다. 물론 찾아볼 필요는 없지만. \t는 위에 있는 데이터에서 "탭 문자"를 나타낸다. 탭 문자란, 키보드의 탭 키를 눌렀을 때 입력되는 글자인데, 탭 키는 키보드 왼쪽의 CapsLock 키 바로 위에 있는 키이다. 이걸 누르면 빈칸이 생기는데, 스페이스 바를 눌러서 나온 빈칸보다는 조금 더 긴 빈칸이 나올 것이다. 이 빈 칸을 탭 문자라고 부른다. 그리고 빈칸을 나타내기 위해서 별다른 방법이 없으므로 \t라는 표현을 사용한 것이다.

# 원래부터 탭이 아니라 쉼표로 저장되어 있는 경우에는 굳이 저렇게 바꿀 필요가 없을 것이다.

# 그 다음 "["과 "]"을 +로 더해주고 있다. 글자를 어떻게 더하느냐고 질문할텐데, 아주 간단하다. 그냥 이어붙이면 된다. 파이썬에서 문자열은 그냥 리스트로 취급된다. 예를 들어서 "abc"+"def"는 "abcdef"가 된다. 그러므로 "["+는 data1의 앞부분에 [를 추가할 것이고 +"]"는 뒷부분에 ]를 추가해줄 것이다.

# 그 다음 밖으로 나와보면 eval이 있다. eval()함수는 아주 신기한 함수인데, 그 안에 있는 글자를 읽어서 파이썬 문법으로 해석해준 결과를 알려준다. 즉, 지금 위와 같은 경우 eval()의 안쪽에 있는 글자는 "[5342, 4551, 34255]"처럼 생긴 문자열이다. 이것은 아직 리스트가 아니다. 저건 저기에 써 있는 글자 그대로를 나타내는 문자열일 뿐이다. 하지만 eval("[5342, 4551, 34255]")이라고 쓰면  이제 저 문자열은 [5342, 4551, 34255] 이라는 리스트가 된다. 그럼 안에 있는 것들도 숫자로 떨어진 5, 3, 4, 2같은 글자가 아니라 5342라는 하나의 수를 나타내는 것이다.

# 그 다음에 numpy.array에다가 그걸 그대로 집어넣었는데, 이것은 numpy.array는 벡터로 취급되어서 우리가 흔히 알던 리스트나 어레이와 다른 행동을 하기 때문이다. 가령 그냥 리스트나 어레이는 [3,5,2]+[6,4,3]를 했을 때 [3, 5, 2, 6, 4, 3]이 된다. 하지만 numpy.array([3,5,2])+numpy.array([6,4,3])는 numpy.array([9, 9, 5])가 된다. 우리는 이것들을 갖고서 이어붙일 것이 아니라 각 항을 갖고 사칙연산을 해야 하기 때문에 이런식으로 작동하는 것은 매우 중요하다. 이게 안되면 매우 괴로웠을 것이다.

# 그럼 len(tmp)는 뭘까? tmp는 어쨌든 어레이의 한 종류인데, len은 그 어레이의 길이를 알려주는 기본 내장 함수이다. 즉 len([5,3,2])는 3이라고 알려준다.

# 그러므로 if len(tmp)==0: 이라고 썼다는 것은 tmp라는 어레이가 텅 비어있는 어레이라는 사실을 알려주는 것이다. 물론 위와 같은 경우, 텅 빈 줄이 데이터 파일의 중간에 들어가 있고, 그 다음에 다시 의미있는 데이터가 이어지는 경우에는 제대로 작동하지 않는다. 이 경우에 어떻게 해야 할지는 각자 생각해 보도록 하자. 알고보면 그다지 어렵지 않다.

# 그럼 이제 dataProcess() 함수를 어떻게 만들어 볼지 알아보자.

def dataProcess(d):
    ...

# 일단 d라는 데이터를 받았고, 이건 한줄짜리 어레이 형태의 값들이다. 어떻게 처리하지?

# http://scipy-lectures.github.io/intro/numpy/index.html 여기에 numpy.array에 대해 여러가지를 알려주는 내용이 있다.

# 평균, 최대값, 최소값, 중앙값, 이런 것들을 찾는 건 그냥 이미 다 되어 있다. 예를 들면,

d.mean() # 이건 d의 평균을 구해서 알려준다.

# 나머지도 한번 알아보자.

# 데이타 처리의 세세한 부분은 데이터의 종류에 따라서 다 다르다. 자신의 데이터를 처리하는 방법은 본인만이 알고 있으므로, 그 방법을 어떻게 하면 파이썬으로 구현할 수 있을지도 자신만이 알 수 있다. 이 부분은 반복 숙달을 통해서 연습하는 것이 최선이다.

by snowall 2013. 7. 28. 19:35