개발/엘리스 AI 트랙

엘리스 AI 트랙 12주차 - 파이썬으로 시작하는 데이터 분석 II (3/18)🔥

Max 2021. 3. 27. 01:32
반응형

✔ 12주차. 데이터 분석 핵심 기법

<학습 목표>

  1. 파이썬 라이브러리인 Pandas, Numpy, Matplotlib의 사용할 수 있습니다.
  2. 파이썬 라이브러리를 활용하여 데이터 분석을 할 수 있습니다.
  3. 데이터를 분석하고 시각화하는 방법을 알수 있습니다.

[01 Pandas 심화 알아보기]

1. 조건으로 검색하기
  - numpy array와 마찬가지로 masking 연산 가능

import numpy as np
import pandas as pd
df = pd.DataFrame(np.random.rand(5, 2), columns=['A', 'B'])
print(df)
#           A         B
# 0  0.609329  0.841142
# 1  0.451572  0.712937
# 2  0.555806  0.667044
# 3  0.113700  0.202053
# 4  0.348867  0.153225

# masking 연산 적용
print(df[(df['A'] < 0.5) & (df['B'] > 0.3)])
#           A         B
# 1  0.451572  0.712937

# query method 사용
print(df.query("A < 0.5 and B > 0.3"))
#           A         B
# 1  0.451572  0.712937

  - 문자열의 경우, 다른 방식으로 조건 검색이 가능 (ex. str.contains(), str.match())
📌 참고  (나중에 이것만 따로 정리할 것!!)

2. 함수로 데이터 처리하기
  - apply 를 사용해 함수로 데이터를 처리함

df = pd.DataFrame(np.arange(5), columns=["Num"])
def square(x):
    return x**2
df["Num"].apply(square)
print(df)
#     Num
# 0    0
# 1    1
# 2    2
# 3    3
# 4    4 

df["Square"] = df.Num.apply(lambda x: x ** 2) # == df["Square"] = df["num"].apply(square)
# 0     0
# 1     1
# 2     4
# 3     9
# 4    16
# Name: Square, dtype: int64

  - replace: apply 기능에서 데이터 값만 대체 하고 싶을때

df = pd.DataFrame(["Male", "Male", "Female", "Female", "Male"], columns=["Sex"])
print(df)
#     Sex
# 0    Male
# 1    Male
# 2  Female
# 3  Female
# 4    Male

# df["Sex"] = df.Sex.replace({"Male": 0, "Female": 1}) 아래 코드와 동일
# df["Sex"] 저장하는 과정없이 기존 dataframe 의 값을 바로 바꿈
df.Sex.replace({"Male": 0, "Female": 1}, inplace=True)
print(df)
#     Sex
# 0    0
# 1    0
# 2    1
# 3    1
# 4    0

3. 그룹으로 묶기
  - 조건부로 집계하고 싶은 경우 사용

df = pd.DataFrame({'key': ['A', 'B', 'C', 'A', 'B', 'C'], 'data': range(6)})
df.groupby('key') # 그룹만 지어진 상태
# <pandas.core.groupby.groupby.DataFrameGroupBy object at 0x10e3588>

print(df.groupby('key').sum())
# 

print(df.groupby(['key','data1']).sum())

  - aggregate

df = pd.DataFrame({
    'key': ['A', 'B', 'C', 'A', 'B', 'C'],
    'data1': [1, 2, 3, 1, 2, 3],
    'data2': [4, 4, 6, 0, 6, 1]
})

# groupby : 집계를 한번에 계산하는 방법
print(df.groupby('key').aggregate(['min', np.median, max]))
#       data1            data2           
#       min median max   min median max
# key                                  
# A       1      1   1     0    2.0   4
# B       2      2   2     4    5.0   6
# C       3      3   3     1    3.5   6

print(df.groupby('key').aggregate({'data1': 'min', 'data2': np.sum}))
#        data1  data2
# key              
# A        1      4
# B        2     10
# C        3      7

# filter : groupby를 통해서 그룹 속성을 기준으로 데이터 필터링
def filter_by_mean(x):
    return x['data2'].mean() > 3
print(df.groupby('key').mean())
#      data1  data2
# key              
# A      1.0    2.0
# B      2.0    5.0
# C      3.0    3.5

print(df.groupby('key').filter(filter_by_mean))
#    key   data1  data2
# 1   B      2      4
# 2   C      3      6
# 4   B      2      6
# 5   C      3      1


# apply : groupby를 통해서 묶인 데이터에 함수 적용
print(df.groupby('key').apply(lambda x: x.max() - x.min()))
#        data1  data2
# key              
# A        0      4
# B        0      2
# C        0      5


# get_group : groupby로 묶인 데이터에서 key값으로 데이터를 가져올 때 사용
print(df.groupby('key').get_group("A"))
#    key   data1  data2
# 0   A      0      4
# 3   A      3      0

3. MultiIndex & pivot_table
  - MultiIndex : Index 를 계층적으로 만들때 사용함(행/열 모두 가능). 인덱스 탐색시 loc, iloc를 사용.

df = pd.DataFrame(
    np.random.randn(4, 2), 
    index=[['A', 'A', 'B', 'B'], [1, 2, 1, 2]],
    columns=['data1', 'data2']
)

print(df1)
#         data1     data2
# A 1 -1.154304  0.841912
#   2 -1.317162 -1.143913
# B 1  0.611612  0.386744
#   2 -0.663984 -0.675955

print(df1.loc['A', 1]) 
# data1   -1.154304
# data2    0.841912
# Name: (A, 1), dtype: float64 

  - pivot_table : 데이터에서 필요한 자료만 뽑아서 새롭게 요약, 분석 할 수 있는 기능(엑셀에서의 피봇 테이블과 같음)
    - Index : 행 인덱스로 들어갈 key
    - Column : 열 인덱스로 라벨링될 값
    - Value : 분석할 데이터

4. 피리 부는 사나이를 따라가는 아이들

df = pd.read_csv("./data/the_pied_piper_of_hamelin.csv")
print(df)

# 피리부는 사나이 데이터에서 마스킹 연산으로 아이들만 뽑아냄
child = df[df["구분"] == "Child"]
print(child)

# 피리부는 사나이를 따라간 아이들의 일차별 연령을 groupby 함수로 계산
print(child.groupby("일차").mean())

# pivot table 사용해 아이들의 일차별 연령을 성별로 나누어 표로 출력
print(child.pivot_table(index="일차", columns="성별", values="나이", aggfunc=np.mean))

# 아이들 이름 데이터만 뽑기
for name in child["이름"].unique():
    print(name)

[02 Matplotlib 데이터 시각화]

1. Matplotlib 소개
  - Matplotlib : 파이썬에서 데이터를 그래프나 차트로 시각화할 수 있는 라이브러리
  - Matplotlib 구조

https://realpython.com/python-matplotlib-guide/

  - 그래프 그려보기

x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 4, 5]
fig, ax = plt.subplots()   # plt.plot(x, y)

# 그래프 이름
ax.set_title("First Plot") # == plt.title("First Plot")

# X축 이름 
ax.set_xlabel("x")  # == plt.xlabel("x")

# Y축 이름
ax.set_ylabel("y")  # == plt.ylabel("y")

# dip 설정
fig.set_dip(300)

# 저장하기
fig.savefig("first_plot.png")

  - 여러개 그래프 그리기

x = np.linspace(0, np.pi*4, 100)

# subplots(세로축, 가로축)
fig, axes = plt.subplots(2, 1)

axes[0].plot(x, np.sin(x))
axes[1].plot(x, np.cos(x))

2. Matplotlib 그래프
  - Line plot

fig, ax = plt.subplots()
x = np.arange(15)
y = x ** 2
ax.plot(
    x, y,
    linestyle=":",
    marker="*",
    color="#524FA1" 
)


  - Line style : linestyle 사용. -(solid), --(dashed), -.(dashdot), :(dotted)
  - Color : 색상의 축약어(red → r, green → g), 색상명(green), 0~1 사이값(grayscale), rgb(#524FA1)
  - Marker : .(점), o(원), v(삼각형), s(네모), *(별)

https://matplotlib.org/3.1.1/gallery/lines_bars_and_markers/marker_reference.html

  - 축 경계 조정하기 : set_xlim(start, end), set_ylim(start, end) 사용
  - 범례 : loc(위치, upper or lower or center / left or right or center), shadow(그림자, T/F), fancybox(모서리, T/F), borderpad(크기)
📌 참고

 3. Scatter
  - Scatter (산점도 그래프)

fig, ax = plt.subplots()
x = np.arange(10)
ax.plot(
    x, x**2, "o",  # x축, y축, 마커
    markersize=15, # 원 크기
    markerfacecolor='white', # 원 안쪽 색
    markeredgecolor="blue"   # 원 바깥쪽 색
)
x = np.random.randn(100)
y = np.random.randn(100)

c = np.random.randint(0, 200, 100)

s = 500 * np.pi * 1 ** 2

ax.scatter(x, y, c=c, s=s, alpha=0.2)

예뻐서 추가..

4. Bar&Histogram
  - Bar plot

# bar graph
x = np.arange(10)
fig, ax = plt.subplots(figsize=(12, 4)) # figsize : 도화지 사이즈
ax.bar(x, x*2)

  - 누적 그래프

x = np.random.rand(3)
y = np.random.rand(3)
z = np.random.rand(3)
data = [x, y, z]

fig, ax = plt.subplots()
x_ax = np.arange(3)
for i in x_ax:
    ax.bar(x_ax, data[i],
    # 이전에 계산한 값 위로 쌓일 수 있도록 함
    bottom = np.sum(data[:i], axis=0))

ax.set_xticks(x_ax)
ax.set_xticklabels(["test1", "test2", "test3"])


  - Histogram (도수분포표)

fig, ax = plt.subplots()
data = np.random.randn(1000)
ax.hist(data, bins=20) # bins : 표시될 막대 갯수

5. Matplotlib with Pandas
  - 미국 대통령 키 그래프

df = pd.read_csv("./president_heights.csv")

fig, ax = plt.subplots()
ax.plot(df["order"], df["height(cm)"], label="height")

ax.legend()
ax.set_xlabel("order")
ax.set_ylabel("height(cm)")

  - 물/불 포켓몬의 공격력과 방어력 그래프

fire = df[(df['Type 1']=='Fire') | ((df['Type 2'])=="Fire")]
water = df[(df['Type 1']=='Water') | ((df['Type 2'])=="Water")]

fig, ax = plt.subplots()

ax.scatter(fire['Attack'], fire['Defense’], color='R', label='Fire', marker="*", s=50)
ax.scatter(water['Attack'], water['Defense’],color='B', label="Water", s=25)

ax.set_xlabel("Attack")
ax.set_ylabel("Defense")
ax.legend(loc="upper right")

6. 토끼와 거북이 경주 결과

# 데이터 파일 읽어오기
df = pd.read_csv("./data/the_hare_and_the_tortoise.csv")

# 첫번째 컬럼을 index 컬럼으로 바꿀때 index_col 사용
# df = pd.read_csv("./data/the_hare_and_the_tortoise.csv", index_col=0)

# 읽어온 데이터를 인덱스로 변경할 때
df.set_index("시간", inplace=True)

# 도화지 세팅
fig, ax = plt.subplots()

# 데이터 세팅
ax.plot(df["토끼"], label="토끼")
ax.plot(df["거북이"], label="거북이")

# 범례 추가
ax.legend()

[03 월드컵 데이터 분석해보기]

1. 데이터 분석
  - 데이터 분석 : 주어진 자료를 가공하여 원하는 정보와 결론을 얻어내는 일련의 처리 과정
  - 데이터 분석의 단계 : 주제 선정 → 데이터 구조 파악 데이터 전처리 → 데이터 분석 구현
    주제 선정 - 어떤 데이터를 선정할 지, 데이터에서 어떤 가설을 세우고 분석을 시작할 지, 어떤 결론을 원하는 지 등 데이터 분석의 목적을 세움
    데이터 구조 파악 - 데이터를 분석하기 위해서, 데이터가 저장된 형태와 자료형, 변수 이름 등을 미리 파악. 또는 데이터 프레임에 통계량 함수를 적용하여, 데이터의 분포도나 성향 등을 파악할 수 있음
     데이터 전처리 - 데이터를 분석하기 전, 필요한 변수만을 추출하거나 기존의 변수로 새로운 변수를 계산하여 만들기도 함. 데이터의 결측값과 이상값이 있다면, 이 단계에서 올바르게 제거하여야 데이터 분석 결과를 올바르게 확인할 수 있음
     데이터 분석 - 주제 선정 단계에서 세운 가설을 numpy, pandas 등으로 데이터를 연산, 가공하여 가설을 입증하거나 원하는 정보를 얻어내는 것을 구현 하는 단계. 얻어낸 정보를 효과적으로 보여주기 위해 시각화하는 경우도 있음.

2. 역대 월드컵의 관중 수 출력하기
  - WorldCups.csv파일을 pandas의 DataFrame으로 만들기
  - 만든 데이터 프레임의 칼럼 중 Year 와 Attendance 칼럼만 추출하여 출력

import pandas as pd
import numpy as np

world_cups = pd.read_csv("WorldCups.csv")

world_cups = world_cups[['Year', 'Attendance']]
print(world_cups)

3. 역대 월드컵의 관중 수

world_cups = pd.read_csv("WorldCups.csv")

world_cups = world_cups[['Year', 'Attendance']]
print(world_cups)

plt.plot(world_cups['Year'], world_cups['Attendance'], marker='o', color='black')

plt.savefig("image.svg", format="svg")

4. 역대 월드컵의 경기당 득점 수
  - WorldCupscsv파일을 pandas의 DataFrame으로 만들기
  - 만든 데이터 프레임의 칼럼 중 Year 와 GoalsScored, MatchesPlayed 칼럼만 추출
  - 데이터 프레임에 경기당 득점 수를 의미하는 새로운 칼럼 GoalsPerMatch를 추가 (GoalsPerMatch = GoalsScored / MatchesPlayed)
  - 데이터 프레임을 출력, 칼럼이 제대로 추가되었는지 확인

world_cups = pd.read_csv("WorldCups.csv")

world_cups = world_cups[['Year', 'GoalsScored', 'MatchesPlayed']]
world_cups['GoalsPerMatch'] = world_cups['GoalsScored'] / world_cups['MatchesPlayed']

print(world_cups)
#     Year  GoalsScored  MatchesPlayed  GoalsPerMatch
# 0   1930           70             18       3.888889
# 1   1934           70             17       4.117647
# 2   1938           84             18       4.666667
# ...

5. 월드컵 매치 데이터 전처리
  - 데이터 전처리를 위해 데이터 프레임의 일부 값을 replace 함수를 사용해 교체
  - 중복값을 제거

world_cups_matches = pd.read_csv('WorldCupMatches.csv')

world_cups_matches = world_cups_matches.replace('Germany FR', 'Germany')

dupli = world_cups_matches.duplicated()
print(len(dupli[dupli==True]))  # 16

world_cups_matches = world_cups_matches.drop_duplicates()
dupli = world_cups_matches.duplicated()
print(len(dupli[dupli==True]))  # 0

6. 국가별 득점 수 구하기
  - 이전에 전처리한 WorldCupMatches.csv 파일이 제공
  - Home Team Name으로 그룹을 묶고, Home Team Goals 칼럼을 추출하여  홈 팀 득점을 나타내는 home에 저장
  - Away Team Name으로 그룹을 묶고, Away Team Goals 칼럼을 추출하여 어웨이 팀 득점을 나타내는 away에 저장
  - concat 메소드로 home, away 데이터 프레임을 하나로 합치고, goal_per_country 라는 새로운 데이터프레임에 저장
  - 결측값을 제거하기 위해 fillna 함수를 적용
  - Home Team Goals와 Away Team Goals 를 덧셈 연산한 값을 Goals에 저장
  - goal_per_country 에서 Goals 칼럼 추출 및 내림차순 정렬. 저장된 값의 dtype를 정수형 변경

world_cups_matches = preprocess.world_cups_matches

home = world_cups_matches.groupby(['Home Team Name'])['Home Team Goals'].sum()
away = world_cups_matches.groupby(['Away Team Name'])['Away Team Goals'].sum()

goal_per_country = pd.concat([home, away], axis=1, sort=True).fillna(0)

goal_per_country['Goals'] = goal_per_country['Home Team Goals'] + goal_per_country['Away Team Goals']

goal_per_country = goal_per_country["Goals"].sort_values(ascending = False)
goal_per_country = goal_per_country.astype(int)

print(goal_per_country)
# Germany                   224
# Brazil                    221
# Argentina                 131
# Italy                     128
# ...

7. 2014 월드컵 다득점 국가 순위
  - 전처리 작업이 된 world_cups_matches 에서 마스킹 연산을 이용하여 Year가 2014인 것들을 추출
  - Home Team Name을 그룹으로 묶어 Home Team Goals의 합계를 구하고 home_team_goal 변수에 저장
  - Away Team Name을 그룹으로 묶어 Away Team Goals의 합계를 구하고 away_team_goal 변수에 저장
  - 홈 득점 수와 원정 득점 수를 하나의 데이터로 합치며, 결측값을 없애기 위해 fillna 함수를 적용 (결측값 = 골X, 0으로 대체)
  - 홈 팀 골과 원정 팀 골 수를 합한 새로운 칼럼 goals를 만들고, 기존 칼럼은 drop 함수를 이용해 삭제
  - 저장된 값을 정수로 변환하고, 데이터 프레임을 내림차순으로 정렬 후 출력

world_cups_matches = preprocess.world_cups_matches

world_cups_matches = world_cups_matches[world_cups_matches['Year']==2014]

home_team_goal = world_cups_matches.groupby(['Home Team Name'])['Home Team Goals'].sum()
away_team_goal = world_cups_matches.groupby(['Away Team Name'])['Away Team Goals'].sum()

team_goal_2014 = pd.concat([home_team_goal, away_team_goal], axis=1).fillna(0)

team_goal_2014['goals'] = team_goal_2014['Home Team Goals'] + team_goal_2014['Away Team Goals']
team_goal_2014 = team_goal_2014.drop(['Home Team Goals', 'Away Team Goals'], axis=1)

team_goal_2014.astype('int')
team_goal_2014 = team_goal_2014['goals'].sort_values(ascending=False)

print(team_goal_2014)
# Germany                   18
# Netherlands               15
# Colombia                  12
# ...

8. 월드컵 4강 이상 성적 집계하기
  - 데이터 프레임에서 역대 대회 1위, 2위, 3위, 4위 추출해 각각 변수 winner, runners_up, third, fourth 저장
  - value_counts 함수로 각 시리즈 데이터에 저장된 값을 세고 저장
  - 위 데이터를 하나의 데이터 프레임으로 합치고 ranks에 들어있는 값이 NaN이라면, 결측값을 0으로 채우고, dtype을 int64로 다시 설정
  - 각 국가들을 우승 횟수, 준우승 횟수, 3위 횟수, 4위 횟수 순서대로 내림차순 정렬

world_cups = pd.read_csv("WorldCups.csv")

winner = world_cups["Winner"]
runners_up = world_cups["Runners-Up"]
third = world_cups["Third"]
fourth = world_cups["Fourth"]

winner_count = pd.Series(winner.value_counts())
runners_up_count = pd.Series(runners_up.value_counts())
third_count = pd.Series(third.value_counts())
fourth_count = pd.Series(fourth.value_counts())

ranks = pd.DataFrame({
  "Winner" : winner_count,
  "Runners_Up" : runners_up_count,
  "Third" : third_count,
  "Fourth" : fourth_count
})

ranks = ranks.fillna(0).astype('int64')
ranks = ranks.sort_values(['Winner', 'Runners_Up', 'Third', 'Fourth'], ascending=False)

print(ranks)
#                 Winner  Runners_Up  Third  Fourth
# Brazil               5           2      2       2
# Germany              4           4      4       1
# Italy                4           2      1       1
# ...


재밌다!!!!

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

반응형