GO WILD, SPEAK LOUD, THINK HARD

엘리스 AI 트랙 13주차 - 파이썬 실전 데이터 분석 II & 프로젝트로 배우는 데이터분석 I (3/24) 🔥 본문

개발/엘리스 AI 트랙

엘리스 AI 트랙 13주차 - 파이썬 실전 데이터 분석 II & 프로젝트로 배우는 데이터분석 I (3/24) 🔥

Max 2021. 3. 29. 21:42
반응형

✔ 실전 데이터를 활용한 데이터 분석

<학습 목표>

  1. 데이터 분석에 파이썬의 조건문, 반복문을 적용하여 익숙하게 사용할 수 있습니다.
  2. 실제적인 데이터들을 분석하고, 시각화하는 방법을 알 수 있습니다.
  3. 다양한 데이터에 대한 정제, 분석 과정을 반복하며 데이터를 수집하고 분석할 수 있습니다.

[01 넷플릭스 시청 데이터로 알아보는 데이터형 변환]

1. 딕셔너리
  - 딕셔너리 : dictionary. { key: value }. key(값을 찾기 위해 넣어 주는 데이터) 와 value(찾고자 하는 데이터)로 구성됨.

# 빈 dict 생성
empty = {}

# 데이터가 있는 dict 생성
elice_dict = { 'Elice' : "엘리스",
               'Cheshire' : "체셔",
               'Mad Hatter' : "모자장수"
             }
print(elice_dict)  # {'Elice': '엘리스', 'Cheshire': '체셔', 'Mad Hatter': '모자장수'}

elice_dict['Heart Queen'] = '하트여왕'
print(elice_dict)
# {'Elice': '엘리스', 'Cheshire': '체셔', 'Mad Hatter': '모자장수', 'Heart Queen': '하트여왕'}


# dictionart vs list
elice_list = [('Elice', '엘리스'), ('Cheshire', '체셔'), ('Mad Hatter', '모자장수')]

print(elice_dict['Mad Hatter'])
for id_, name in elice_list:  # dict 에 비해 더 오랜 시간이 걸림
    if id_ == "Mad Hatter":
    	print(name)

  - 데이터 빠르게 탐색하기 : {사용자 번호: 작품 번호}로 이루어진 netflix.txt을 읽고, 사용자 번호를 키로, 작품 번호를 값으로 하는 딕셔너리를 생성하는 make_dictionary() 함수를 완성할 것.

source_file = "netflix.txt"

def make_dictionary(filename):
    user_to_titles = {}
    with open(filename) as file:
        for line in file:
            user, title = line.strip().split(":")
            user_to_titles[user] = title
            
        return user_to_titles

2. 딕셔너리의 키 
  - 딕셔너리의 키는 변할 수 없는 값 만이 될 수 있음 (ex. tuple 등)

# 딕셔너리의 키 확인하기
print('elice' in elice_dict) # False
print('Elice' in elice_dict) # True

# 딕셔너리 순회하기
for id_, name in elice_dict.items():
	print(id_ + "-" + name)   # Elice-엘리스
                              # Cheshire-체셔
                              # ...

  - 데이터 순회하기 : {사용자: [작품 리스트]} 형식으로 저장된 딕셔너리를 {사용자: 본 작품의 수}로 변환하는 함수를 작성하기

# 사용자가 시청한 작품의 리스트
user_to_titles = {
    1: [271, 318, 491],
    2: [318, 19, 2980, 475],
    3: [475],
    4: [271, 318, 491, 2980, 19, 318, 475],
    5: [882, 91, 2980, 557, 35],
}
def get_user_to_num_titles(user_to_titles):
    user_to_num_titles = {}
    
    for key, val in user_to_titles.items():
        user_to_num_titles[key] = len(val)
    
    return user_to_num_titles

print(get_user_to_num_titles(user_to_titles)) # {1: 3, 2: 4, 3: 1, 4: 7, 5: 5}

3. JSON
   - JSON : JavaScript Object Notation. { key : value } 형태로 이루어져 있음.
  - JSON 특징

    ① 웹 환경에서 데이터를 주고 받는 가장 표준적인 방식
    ② 키를 이용하여 원하는 데이터만 빠르게 추출 가능
    ③ 데이터가 쉽게 오염되지 않음
    ④ 다른 포맷에 비해 용량이 조금 큰 편
 📌 참고하기
  -  JSON과 딕셔너리 변환 : JSON → loads() → 딕셔너리 / JSON ← dumps() ← 딕셔너리
  - JSON 데이터 읽고 생성하기

# json 패키지 임포트
import json

#JSON 파일을 읽고 문자열을 딕셔너리로 변환
def create_dict(filename):
    
    with open(filename) as file:
        json_string = file.read() # file 내용을 한꺼번에 불러옴

        # 불러온 결과 = str / dict 변환 하기 위해서 json.loads 사용
        return json.loads(json_string)


#JSON 파일을 읽고 딕셔너리를 JSON 형태의 문자열로 변환
def create_json(dictionary, filename):
    with open(filename, 'w') as file:
        file.write(json.dumps(dictionary))

4. 집합
  - 집합 : Set. 중복&순서 X

set1 = {1, 2, 3}
set2 = set([3, 2, 1])
print(set1 == set2)  # True

set3 = {1, 2, 3, 1}
print(set3)  # {1, 2, 3}

num_set = {1, 3, 5, 7} 

# 원소 추가
num_set.add(9) 
print(num_set)  # {1, 3, 5, 7, 9}

# 원소 여러개 추가
num_set.update([3, 15, 4]) 
print(num_set)  # {1, 3, 4, 5, 7, 9, 15}

# 원소 삭제하기 (원소가 없다면 error)
num_set.remove(6) 
print(num_set)  # KeyError: 6

# 원소 삭제하기 (원소가 없다면 무시)
num_set.discard(13)
print(num_set)  # {1, 3, 4, 5, 7, 9, 15}

print(6 in num_set) # False
print(len(num_set)) # 7

divide_set = {num for num in num_set if num % 2 != 0}
print(divide_set) # {1, 3, 5, 7, 9, 15}

5. 집합연산
  - 합집합 (|), 교집합(&), 차집합(-), XOR(^)
📌 참고하기 ☞ www.geeksforgeeks.org/python-bitwise-operators/

6. 그래프 다루기

import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

# 날짜 별 온도 데이터를 세팅합니다.
dates = ["1월 {}일".format(day) for day in range(1, 32)]
temperatures = list(range(1, 32))

# 막대 그래프의 막대 위치를 결정하는 pos를 선언합니다.
pos = range(len(dates))

# 한국어를 보기 좋게 표시할 수 있도록 폰트를 설정합니다.
font = fm.FontProperties(fname='./NanumBarunGothic.ttf')

# 막대의 높이가 빈도의 값이 되도록 설정합니다.
plt.bar(pos, temperatures, align='center')

# 각 막대에 해당되는 단어를 입력합니다.     ↓ 폰트사용시 추가
plt.xticks(pos, dates, rotation='vertical', fontproperties=font)

# 그래프의 제목을 설정합니다.
plt.title('1월 중 기온 변화', fontproperties=font)

# Y축에 설명을 추가합니다.
plt.ylabel('온도', fontproperties=font)

# 단어가 잘리지 않도록 여백을 조정합니다.
plt.tight_layout()

# 그래프를 표시합니다.
plt.savefig('graph.png')

7. 넷플릭스 시청 데이터 분석하기
  - preprocess_data(filename) : 입력 받은 JSON 형식의 데이터를 딕셔너리 형태로 변환후 반환 (key는 정수로 설정). JSON 데이터의 key는 영화 id, value는 유저 id가 담긴 리스트로 구성되어 있으며 각 영화 id에 대해 해당 영화를 시청한 유저들의 id를 담고 있는 리스트가 매칭된 딕셔너리를 반환해야 함.
  - reformat_data(title_to_users) : 작품 별 시청한 사용자 데이터인 title_to_users가 주어지면 사용자 별 시청 작품이 각각 key와 value로 담긴 딕셔너리로 반환
  - get_closeness(title_to_users, title1, title2) : 두 작품의 유사도를 구함. 유사도는 (두 작품을 모두 본 사용자) / (두 작품 중 하나라도 본 사용자)
  - predict_preference(title_to_users, user_to_titles, user, title) : 작품1과 사용자A가 주어졌을 때, 예상 선호도를 계산. 작품1에 대한 사용자A의 예상 선호도는 사용자A가 시청한 모든 작품과 작품1 유사도의 평균값임

import json

def preprocess_data(filename):
    processed = {}
    with open(filename) as file:
        loaded = file.read()
        json_loaded = json.loads(loaded)
        for title, user in json_loaded.items():
            processed[int(title)] = user
    
    return processed

def reformat_data(title_to_users):
    
    user_to_titles = {}
    for title, users in title_to_users.items():
        for user in users:
            if user in user_to_titles:
                user_to_titles[user].append(title)
            else:
                user_to_titles[user] = [title]
                
    return user_to_titles


def get_closeness(title_to_users, title1, title2):
    title1_users = set(title_to_users[title1])
    title2_users = set(title_to_users[title2])
    
    both = len(title1_users & title2_users)
    either = len(title1_users | title2_users)

    return both / either

def predict_preference(title_to_users, user_to_titles, user, title):
    titles = user_to_titles[user]
    closeness = [get_closeness(title_to_users, title, num) for num in titles]

    return sum(closeness) / len(closeness)

[02 테드 강연으로 다뤄보는 복잡한 형태의 데이터]

1. CSV
  - CSV : Comma Separated Value. 각 열이 특정한 의미를 가짐. 파일을 읽을때는 reader  사용

# movies.csv
# 국문 제목,영문 제목,개봉 연도 (다른 구분 문자(delimiter)도 사용 가능)
# 다크나이트,The Dark Knight,2008 
# 겨울왕국,Frozen,2013 
# 슈렉,Shrek,2001 
# 슈퍼맨,Superman,1978

# 영어 제목에 , 들어있을 경우
# 먹고 기도하고 사랑하라,"Eat, Pray, Love",2010

  - 장점 : 같은 데이터를 저장하는데 용량을 적게 사용 / 단점 : 데이터 오염에 취약
  - CSV 데이터 읽고 처리하기 : 책 정보가 담긴 CSV 파일의 데이터를 ,를 기준으로 분리하고 제목 (저자): 페이지 수p 형식으로 출력하는 함수를 완성

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

  - CSV 데이터 JSON으로 변환하기

import csv
import json

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:
        dst.write(json.dumps(books))

2. lambda
  - lambda : 일종의 연산자, 문법. 함수를 만드는 또다른 방법.
📌 연습하기 ☞ www.w3schools.com/python/python_lambda.asp
  - assert() : T/F return. T는 그냥 넘어가고 F는 Error 발생

# _square()와 square()는 동일한 기능
def _square(num):
    return num * 2

square = lambda x : x * x

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

  - 함수를 리턴하는 함수
    - min_validator : 주어진 값이 정수가 아니거나 최솟값 minimum보다 작으면 False를 리턴
    - max_validator : 주어진 값이 정수가 아니거나 최댓값 maximum보다 크면 False를 리턴

def min_validator(minimum):
    def helper(n):
        if type(n) is not int:
            return False
        return minimum <= n
    
    return helper

def max_validator(maximum):
    def helper(n):
        if type(n) is not int:
            return False
        return maximum >= n
    
    return helper

def validate(n, validators):
    for validator in validators:
        if not validator(n):
            return False
    
    return True

3. map
  - map : 리스트나 데이터의 집합이 주어졌을 때, 데이터의 원소들에 대해서 동일한 함수를 취해주는 것.

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

# movies 리스트의 영화제목을 영어 제목으로 변경하는 방법1
def get_eng_title(row):
    split = row.split(',') 
    return split[1] 

eng_titles = [get_eng_title(row) for row in movies]

# movies 리스트의 영화제목을 영어 제목으로 변경하는 방법2
eng_titles = [row.split(',')[1] for row in movies] 

# movies 리스트의 영화제목을 영어 제목으로 변경하는 방법3
eng_titles = map(get_eng_title, movies)

# movies 리스트의 영화제목을 영어 제목으로 변경하는 방법4
eng_titles = map(lambda row: row.split(',')[1], movies)

  - 리스트에 함수 적용하기 : 파일을 읽어서 제목의 리스트를 리턴하는 get_titles() 함수를 완성

import csv

def get_titles(books_csv):
    with open(books_csv) as books:
        reader = csv.reader(books, delimiter=',')
        
        # 바로 실행하는 함수X
        get_title = lambda x: x[0] # 밑에 titles 에서 map 으로 사용할 함수를 미리 만들어 둔 것
        # reader 데이터에 각 줄에 대해서 get_title 함수를 사용하는 것임
        titles = map(get_title, reader) # => 아래 for 문 부분
        
        # titles = []
        # for row in reader:
        #     titles.append(get_title(row))
        
        return list(titles)

books = 'books.csv'
titles = get_titles(books)

4. filter
  - filter : map과 비슷하게 list나 데이터 집합에 대해서 사용하는 함수. map 처럼 계산해서 값이 true 라면 그 값을 모아줌.

# words 리스트에서 r로 시작하는 단어를 찾음
words = ['real', 'man', 'rhythm', 'apple', 'left', 'right'] 

# list comprehension 사용
r_words = [word for word in words if word.startswith('r')]

# filter 사용
def starts_with_r(word): 
    return word.startswith('r') 

r_words = filter(starts_with_r, words)

# lambda 와 filter 사용
starts_with_r = lambda w: w.startswith('r') 

r_words = filter(starts_with_r, words)

  - 리스트에 함수 적용하기 : 파일을 읽고 페이지 수가 250 넘는 책 제목만 리스트로 리턴하는 함수 완성하기

import csv

def get_titles_of_long_books(books_csv):
    with open(books_csv) as books:
        reader = csv.reader(books, delimiter=',')
        
        # 함수만 정의. 바로 실행하는 것X
        # 페이지가 250 넘는지 확인
        is_long = lambda row: int(row[3]) > 250
        # 책 이름 가져오기
        get_title = lambda row: row[0]
        
        # reader 데이터에서 is_long 함수를 사용해서 페이지 250 넘는 것만 체크
        long_books = filter(is_long, reader)
        # long_books 으로 filtering 한 데이터에서 title만 가져옴
        long_book_titles = map(get_title, long_books)
        
        return list(long_book_titles)

5. 인기 있는 TED 강연 분석하기
  - preprocess_talks(csv_file) : 주어진 CSV 파일을 열어 처리 가능한 파이썬의 리스트 형태로 변환.
  - get_popular_tags(talks, n) : 가장 인기 있는 태그 상위 n개를 반환. 태그의 인기도는 해당 태그를 포함하는 강의들의 조회수 합임.
  - completion_rate_by_duration(talks) : 강연의 길이에 따라 강의를 끝까지 들은 비율(완수도)이 어떻게 변화하는지 확인. 강의를 끝까지 들은 비율은 (댓글 개수 / 조회수)에 비례한다고 가정. 완수도를 나타내는 completion_rates와 강의 길이를 나타내는 duration을 반환
  - views_by_languages(talks) : 지원되는 언어의 수에 따른 조회수를 scatter plot으로 나타내기 위해 각각의 언어와 조회수를 세어 반환
  - show_ratings(talk) : 강의에 대한 다양한 평가(rating)를 막대그래프로 표현하기 위해 각각의 평가 키워드와 횟수를 세어 반환

[03 프로젝트 준비하기]

1. 프로젝트와 데이터 분석
  - 데이터 : 현실 세계의 일들을 관찰, 측정해서 얻은 값
  - 정보 : 데이터를 처리해서 얻는 의미 있는 값
  - 데이터 분석 : 데이터를 활용하여 원하는 정보를 얻어내기 위한 일련의 과정
  - 데이터 분석 프로젝트 : 문제 정의 → 가설 설정 → 데이터 준비 → 데이터 분석 → 결과 정리

2. 프로젝트 준비하기
  - Jupyter Notebook

2021.03.28 - [개발] - Jupyter Notebook

 

Jupyter Notebook

기술 블로그 Jupyter Notebook 본문 개발 Jupyter Notebook Max 2021. 3. 28. 17:15 Prev 1 2 3 4 5 6 ··· 51 Next

developer-max.tistory.com

  - Markdown

2021.03.28 - [개발] - Markdown 사용하기

 

Markdown 사용하기

기술 블로그 Markdown 사용하기 본문 개발 Markdown 사용하기 Max 2021. 3. 28. 17:22 Prev 1 2 3 4 5 ··· 51 Next

developer-max.tistory.com

[04 데이터 분석 시작하기]

1. 데이터 분석 프로세스
  - 데이터 분석 : 데이터를 활용하여 원하는 정보를 얻어내기 위한 일련의 과정
  - 데이터 분석 과정 : 문제 정의 → 가설 설정 → 데이터 준비 → 데이터 분석 → 결과 정리
    ① 문제 정의 - 현재 풀고자 하는 문제가 무엇인지를 명확히 정의
    ② 가설 설정 - 문제를 해결하기 위한 데이터 분석의 토대인 가설 설정 (문제와의 관련성 고려)
    ③ 데이터 준비 - 풀고 싶은 문제에 대한 정보를 담고 있는 데이터셋을 선정 (데이터 수집 및 전처리 과정)
        → 데이터 정제 (Data Cleaning) : 빠진 부분, 중복, 이상값 제거, 형태 변환 등의 초기 데이터(Raw Data)전처리 시행
    ④ 데이터 분석 - 본격적인 데이터 분석. 데이터 분석 프로젝트의 성공여부는 얼마나 데이터를 이해하고 있느냐에 좌우됨
        → 탐색적 데이터 분석(EDA) : Exploratory Data Analysis. 데이터의 특징을 찾고, 숨겨진 패턴을 발견하는 과정
    결과 정리- 분석 과정에서 알아낸 인사이트(Insight) 정리
📌 문제 해결을 위한 의미 있는 데이터 분석이 필요하며, 명확한 목표 설정과 목표에 맞는 흐름에 따른 데이터 분석 진행을 해야 함.
 
2. 데이터 분석 도구
  - Excel, Python, R,  SAS 등등..
  - Python : 범용적이며 데이터 분석을 위한 라이브러리 지원
  - Python Library : pandas, matplotlib 등등


※ 수업 자료의 출처는 K-Digital Training x 엘리스 인공지능 서비스 개발 기획 1기 (elice.io/)입니다.

반응형
Comments