티스토리 뷰

개발공부/🎅 Python

[Python] TED 강연을 통해 접해 보는 복잡한 형태의 데이터

2022. 9. 23. 23:15

1️⃣  CSV

 

Comma Separated Value

 

 

-  각 열이 특정한 의미를 가진다.

# movies.csv 
# 국문 제목,영문 제목,개봉 연도

다크나이트,The Dark Knight,2008 
겨울왕국,Frozen,2013 
슈렉,Shrek,2001 
슈퍼맨,Superman,1978

 

 

-  다른 구분 문자(delimiter)도 사용 가능하다.

# movies.csv 

다크나이트|The Dark Knight|2008 
겨울왕국|Frozen|2013 
슈렉|Shrek|2001 
슈퍼맨|Superman|1978

 

 

-  데이터에 ,가 포함된 경우 큰따옴표 (" ") 를 이용하여 데이터를 감싼다

# movies.csv 

먹고 기도하고 사랑하라,"Eat, Pray, Love",2010
"헬로우, 뉴욕","Hello, New York",2013

 

 

-  같은 데이터를 저장하는 데 용량을 적게 소모한다.

# movies.csv 
아이언맨,Iron Man,2008 
겨울왕국,Frozen,2013 

# movies.json 
[{"ko": "아이언맨", "en": "Iron Man", "year": 2008}, 
{"ko": "겨울왕국, "en": "Frozen", "year": 2013}]

 

 

 

-  데이터 오염에 취약하다.  →  ,를 하나를 잘못써도 전체 데이터가 망가진다

# movies.csv 
아이언맨,Iron, Man,2008 
겨울왕국,Frozen,2013

 

-  엑셀에서 csv파일을 열 수 있다.  →  시각화를 하기 좋다.

 

 

 

 

CSV 읽어오기

import csv

with open('movies.csv') as file: 
    reader = csv.reader(file, delimiter=',') 
    
    for row in reader: 
        print(row[0])

 

 

 

 

 

 

▶  CSV 데이터를 분석하기 위해 각 열의 데이터를 분리

import csv

def print_book_info(filename):
    with open(filename) as file:
        reader = csv.reader(file, delimiter=',')
        
        for row in reader:
            title = row[0]
            author = row[1]
            pages = row[3]
            print("{} ({}): {}p".format(title, author, pages))

filename = 'books.csv'
print_book_info(filename)

 

 

▶  CSV는 파일의 크기가 작다는 장점을 갖고 있지만, 상황에 따라 JSON 같은 다른 형식으로 변환하여 주고받아야 한다.

import csv
import json
from elice_utils import EliceUtils

elice_utils = EliceUtils()

def books_to_json(src_file, dst_file):
    books = []
    with open(src_file) as src:
        reader = csv.reader(src, delimiter=',')
        
        for row in reader:
            book = {
                'title': row[0],
                'author': row[1],
                'genre': row[2],
                'pages': int(row[3]),
                'publisher': row[4]
            }
            books.append(book)
    
    with open(dst_file, 'w') as dst:
        json_string = json.dumps(books)
        dst.write(json_string)

src_file = 'books.csv'
dst_file = 'books.json'
books_to_json(src_file, dst_file)
elice_utils.send_file(dst_file)

 

 

 

 

 

2️⃣  고급 파이썬

 

lambda

lambda 인자: 표현식

-  익명함수

-  일회용

 

 

예시1)

# 일반 함수
def square(x): 
    return x * x 

# lambda 함수
square = lambda x: x * x

 

 

예시2)

# 1
def get_eng_title(row): 
    split = row.split(',') 
    return split[1] 
sorted(movies, key=get_eng_title)

# 2
get_eng_title = lambda row: row.split(',')[1] 
sorted(movies, key=get_eng_title)

# 3
sorted(movies, key=lambda row: row.split(',')[1])

 

 

예시3)

def square1(x): 
    return x * x 
    
square2 = lambda x: x * x

# 두 값이 같으면 통과, 아니면 에러
assert(square1(3) == square2(3))

-  assert()  :  조건이 True인 경우 그대로 코드 진행, False인 경우 AssertError 발생

 

 

 

 

 

 

map

 

데이터 구조의 각 원소들에 동일한 함수를 적용하여 새로운 데이터를 만드는 파이썬의 기본 함수

list = [x, y, z]

map(f, list)	# [f(x), f(y), f(z)]

 

예시)

movies = [ 
    "다크나이트,The Dark Knight,2008",
    "겨울왕국,Frozen,2013", 
    "슈렉,Shrek,2001", 
    "슈퍼맨,Superman,1978" 
]

eng_titles = [ 
    "The Dark Knight",
    "Frozen", 
    "Shrek", 
    "Superman" 
]

# 방법1) list comprehension
def get_eng_title(row): 
    split = row.split(',') 
    return split[1] 
eng_titles = [get_eng_title(row) for row in movies]
    
# 방법2) map
def get_eng_title(row): 
    split = row.split(',') 
    return split[1] 
eng_titles = map(get_eng_title, movies)

# 방법3) lambda
eng_titles = map( 
    lambda row: row.split(',')[1], 
    movies 
)

 

 

-  리스트가 아닌 map이라는 타입을 가진다.

eng_titles = map(get_eng_title, movies) 
print(eng_titles)	# <map object at 0x104154f98>

map은 실제로 리스트를 바로 만드는게 아니라 map이라는 타입을 가진 새로운 데이터 구조를 만들어 놓는 것.

사용자가 원소를 찾을 때(ex. eng_titles[0] 할 때) 그 때 함수를 적용해서 새롭게 원소를 만들어준다.

→  list보다 빠르다.

 

 

List comprehension과 map()은 유사한 연산을 하지만 연산을 진행하는 시점이 다르다. 

→  map()의 경우 데이터를 map이라는 클래스로 저장하고, 데이터가 필요해질 때 주어진 연산을 수행합니다.

 

 

 

 

 

 

filter

 

주어진 데이터 구조에서 특정 조건을 만족하는 원소만 골라내는 파이썬의 기본 함수

words = ['real', 'man', 'rhythm', ...] 

# 방법1
r_words = [word for word in words if word.startswith('r')]

# 방법2
def starts_with_r(word): 
    return word.startswith('r')
r_words = filter(starts_with_r, words)

# 방법3
starts_with_r = lambda w: w.startswith('r')
r_words = filter(starts_with_r, words)

 

 

-  리스트가 아닌 filter 타입을 가진다.

r_words = filter(starts_with_r, words) 
print(r_words)	# <filter object at 0x104154f98>

filter()도 map()과 마찬가지로 즉시 연산되지 않고 filter 타입의 데이터 구조를 생성한다.

 

 

 

 

 

 

 

▶   def로 선언된 함수를 동일한 기능을 가진 lambda 함수로 선언

# num을 제곱한 값을 리턴
def _square(num):
    return num * num

square = lambda num: num*num


# string이 빈 문자열일 경우 빈 문자열을, 아니면 첫 번째 글자를 리턴
def _first_letter(string):
    return string[0] if string else ''

first_letter = lambda string: string[0] if string else ''


# assert를 이용하여 두 함수의 기능이 동일한 지 테스트
testcases1 = [3, 10, 7, 1, -5]
for num in testcases1:
    assert(_square(num) == square(num))

testcases2 = ['', 'hello', 'elice', 'abracadabra', '  abcd  ']
for string in testcases2:
    assert(_first_letter(string) == first_letter(string))

print("성공했습니다!")

 

 

▶  데이터가 특정 범위에 속하는 유효한 값인지 검증하는 Validator 함수 (함수를 리턴하는 함수)

# 주어진 값이 정수가 아니거나 최솟값 minimum보다 작으면 False를 리턴하는 함수를 리턴
def min_validator(minimum):
    def helper(n):
        if type(n) is not int:
            return False
        return minimum <= n
        
    return helper
  
# 주어진 값이 정수가 아니거나 최댓값 maximum보다 크면 False를 리턴하는 함수를 리턴
def max_validator(maximum):
    def helper(n):
        if type(n) is not int:
            return False
        return maximum >= n
    
    return helper

# validator 중 하나라도 통과하지 못하면 False를 리턴
def validate(n, validators):
    for validator in validators:
        if not validator(n):
            return False
    
    return True


# 작성한 함수 테스트
age_validators = [min_validator(0), max_validator(120)]
ages = [9, -3, 7, 33, 18, 1999, 287, 0, 13]

print("검증 결과")
for age in ages:
    result = "유효함" if validate(age, age_validators) else "유효하지 않음"
    print("{}세 : {}".format(age, result))

 

 

▶  books.csv 파일을 읽어서 제목의 리스트를 리턴

import csv

def get_titles(books_csv):
    with open(books_csv) as books:
        reader = csv.reader(books, delimiter=',')
=
        get_title = lambda row: row[0]
        titles = map(get_title, reader)
        
        return list(titles)
        # return하는 순간 with문이 끝나고 파일이 닫힘
        # map은 원소를 가져올때나 print할 때 연산이 되는데
        # 그때는 이미 파일이 close되어있음 -> 파일에 접근하려면 에러 발생
        # 그래서 list로 변환해주면 그 즉시 map이 실행됨

books = 'books.csv'
titles = get_titles(books)
for title in titles:
    print(title)

 

 

▶  books.csv 파일을 읽어서 페이지 수가 250이 넘는 책들의 제목을 리스트로 리턴

import csv

def get_titles_of_long_books(books_csv):
    with open(books_csv) as books:
        reader = csv.reader(books, delimiter=',')
        
        is_long = lambda row: int(row[3]) > 250
        get_title = lambda row: row[0]
        
        long_books = filter(is_long, reader)
        long_book_titles = map(get_title, long_books)
        
        return list(long_book_titles)
        # filter도 map과 같이 연산을 나중에 하기 때문에 파일이 닫힌 다음에는 접근불가
        # list()를 이용해서 return하는 시점에 읽어올 수 있도록

books  = 'books.csv'
titles = get_titles_of_long_books(books)
for title in titles:
    print(title)

 

 

 


 이 글은 엘리스의 AI트랙 5기 강의를 들으며 정리한 내용입니다.

 

반응형
프로필사진
개발자 삐롱히

프론트엔드 개발자 삐롱히의 개발 & 공부 기록 블로그