배꼽파지 않도록 잘 개발해요

[코드잇] 데이터 사이언스 기초 - 데이터 분석과 시각화 본문

카테고리 없음

[코드잇] 데이터 사이언스 기초 - 데이터 분석과 시각화

꼽파 2023. 9. 21. 09:30


  • 1. 시각화와 그래프

  • 2. Seaborn 시각화

  • 3. 통계 기본 상식

  • 4. Exploratory Data Analysis

  • 5. 새로운 인사이트 발견하기

  • 1. 시각화와 그래프

    시각화의 두 가지 목적

    1. 시각화는 분석에 도움을 줌. 2. 리포팅에 도움이 된다.
    · 그래프는 패턴을 발견하기 쉬워서 의사결정에 도움이 됨.
    · 시각화를 하면 보이지 않는 문제들이 보이기 시작함.
    ex. 데이터 하나만 동떨어져 있는 경우(이상점, outlier) → 심층 분석 
    · 리포팅 : 데이터에 대해 보고하는 것
    · 숫자 정보만 있으면 직관적으로 이해가 되지 않음.
    · 예뻐서 집중해서 쳐다보므로 커뮤니케이션에 도움이 됨.

    선그래프

    x축에는 보통 시간과 관련된 값이 들어감.
    문자에 대해서 그래프를 그리려고 하면 오류가 발생함.

    %matplotlib inline
    import pandas as pd
    
    df = pd.read_csv(r'C:\Users\airyt\Downloads/sports.csv', index_col=0)
    
    df.plot()  
    df.plot(kind='line') # 선그래프가 기본이기 때문에 파라미터는 생략해도 됨.
    
    df.plot(y='KBS')  # KBS에 대한 선 '하나만' 나옴
    df.plot(y=[ 'KBS', 'JTBC' ])  # 원소가 여러개일 경우는 리스트로 넘겨주기  
    
    # df불러오고 .plot() 메소드 이용
    df[['KBS', 'JTBC']].plot()  # 여러 개의 df
    df['KBS'].plot()  # 한 개의 df

    막대 그래프

    카테고리 비교를 위해 사용함.

    df.plot()  # 기본 설정이 선그래프임.
    
    df.plot(kind='bar')  # 막대그래프가 나옴.
    
    df.plot(kind='barh')  # h = horizontal의 약자
    
    df.plot(kind='bar', stacked=True)  # 막대가 쌓여서 나옴 → 총계가 한눈에 보임
    
    df['Female'].plot(kind='bar')  # 여성에 대한 그래프만 나옴.

     

    그래프 그리기 

    %matplotlib inline
    import pandas as pd
    
    df = pd.read_csv('data/silicon_valley_summary.csv')
    
    # 각 조건을 변수 A, B, C에 불린값으로 저장
    A = (df['job_category'] == 'Managers')
    B = (df['gender'] == 'Male')
    C = (df['race_ethnicity'] != 'All')
    
    # 불린값을 넣어주어 조건에 맞는 데이터 추출 → 그래프 그리기
    df[A & B & C].plot(kind='bar', x='race_ethnicity',  y='count')
    
    '''
    df.loc[A & B & C].plot(kind='bar', x='race_ethnicity',  y='count')
    → 결과가 동일하게 나온다
    '''

     

    Pandas 리스트로 인덱싱할 때 문제점 

    %matplotlib inline
    import pandas as pd
    
    df = pd.read_csv('data/silicon_valley_summary.csv', index_col=1)
    
    # 인덱스(행)에서 'All'부분은 제외
    f_df = df[ df.index != 'All']
    
    # 원하는 조건의 데이터만 추출 (managers, male, 그래프: count, race_ethnicity)
    c = f_df.loc[ (f_df['job_category'] == 'Managers') & ( f_df['gender'] == 'Male'), 
    ['count', 'race_ethnicity']]
    
    # 그래프 그리기
    c.plot(kind='bar', x='race_ethnicity', y='count')  # x축 지정 안 해줘도 나오긴 함.

     

    오류나는 코드

    %matplotlib inline
    import pandas as pd
    
    df = pd.read_csv('data/silicon_valley_summary.csv'. index_col=1)
    
    d_manager = (df['job_category'] == 'Managers')
    d_male = (df['gender'] == 'Male')
    d_except = (df.index != 'All')
    
    df[d_manager & d_male & d_except].plot(kind='bar', x='race_ethnicity',  y='count')
    
    # 이미 index로 race_ethnicity column이 지정되어서
    # 마지막에 x축으로 race_ethnicity를 지정할 때 에러가 발생함.

    파이 그래프

    절대적인 수치보다 비율을 표현하기에 좋음.
    ex. 선거 결과 : 몇 표(수치) < 몇 퍼센트 (비중)

    df.loc[2017].plot(kind='pie')  # 파이 그래프 출력
    %matplotlib inline
    import pandas as pd
    
    df = pd.read_csv('data/silicon_valley_details.csv')
    
    # 불린값을 변수에 저장
    A = df['company'] == 'Adobe'
    B = df['count'] != 0
    C = df['job_category'] != 'Totals'
    D = df['job_category'] != 'Previous_totals'
    E = df['race'] == 'Overall_totals'
    
    # 원하는 데이터프레임 출력
    n_df = df[ A & B & C & D & E ][['job_category', 'count']]
    
    # 인덱스 변경 (파이 그래프 그리기 위해)
    n_df.set_index('job_category', inplace=True)
    
    # 파이그래프 그리기 (y값도 지정해줘야 함)
    n_df.plot(kind='pie', y='count')
    df[ A & B & C & D & E ][['job_category', 'count']] n_df = df[ A & B & C & D & E ][['job_category', 'count']]
    n_df.set_index('job_category', inplace=True)

    파이 그래프는 index를 기준으로 이름표를 달아줌,

    set_index(keys, inplace=True)로 인덱스 변경해야함.


    히스토그램

    1,000명의 학생을 대상으로 키를 조사함.
    · 막대그래프 : 항목비교, 키(항목)이 너무 많아짐.
    · 파이그래프 : 차지하는 비율, 키(항목)이 너무 많아짐.
    → 히스토그램 사용

    • 히스토그램에서는 키를 각각의 항목으로 두는 것이 아니라 범위로 묶어서 봄.
    대략적인 값들의 분포를 한번에 알 수 있음.

    df.plot(kind='hist', y='Height')  # 보고 싶은 컬럼 = y축
    
    df.plot(kind='hist', y='Height', bins=20)  
    # bins: 히스토그램의 가로축 구간의 개수 → 막대기가 20개
    # 상황에 맞는 적당한 숫자 찾기

     


    박스 플롯

    데이터 정보에 대한 통계 정보를 시각적으로 보여주기 위해 사용됨.
    총 5개의 통계값으로 데이터 셋을 요약함.

    # 통계 수치 요약
    df['math score'].describe()
    
    # 한 항목에 대한 박스 플롯 생성
    df.plot(kind='box', y='math score')
    
    # 여러 항목에 대한 박스 플롯 생성
    df.plot(kind='box', y=['math score', 'reading score', 'writing score'])
    
    # 위스커(상위25%, 하위25%)가 길다 = 해당 구간은 점수가 분산되어 있다

    산점도(scatter plot)

    상관관계를 보여주기 적합함.

    ex. 행복지수와 등수, 몸무게와 키 등이 서로 연관이 있는지
    모양을 보고 연관성을 찾을 수 있음.

    df.plot(kind='scatter', x='reading score', y='writing score')

    2. Seaborn 시각화

    Seaborn

    Statistical Data Visualization (통계를 기반으로 한 데이터 시각화)

    pandas보다 더 다양하고 근사한 그래프를 그릴 수 있음.

    https://seaborn.pydata.org/

     

    seaborn: statistical data visualization — seaborn 0.12.2 documentation

    seaborn: statistical data visualization

    seaborn.pydata.org


    확률 밀도 함수 (PDF)

    Probability Density Function 
    데이터셋의 분포를 나타냄. (히스토그램의 막대수를 무한으로 늘리면 거의 비슷해짐.)
    특정 구간의 확률은 그래프 아래 그 구간의 면적과 동일함.
    그래프 아래의 모든 면적을 더하면 1임.
    특정 에 대한 확률 구하기 (X), 특정 범위에 대한 확률 (O)


    KDE Plot

    # seaborn 설치
    !pip install seaborn == 0.9.0
    
    # 각 키가 몇 번 나오는지 빈도 출력
    body_df['height'].value_counts()  
    
    # 인덱스 순으로 정렬 → .sort_index()  
    body_df['height'].value_counts().sort_index()  
    
    # 그래프 그리기 → .plot()
    body_df['height'].value_counts().sort_index().plot()
    
    # seaborn 라이브러리의 kedplot 사용 → sns.kdeplot()
    sns.kdeplot(body_df['height'])
    
    # bw 파라미터
    '''
    seaborn으로 그린 그래프는 실제 데이터 분포와 다름.
    추측을 어느 정도 할지 설정할 수 있음.
    seaborn으로 그린 그래프는 "bw 파라미터" 사용
    bw가 "작을수록" 분포 표현을 Histogram과 가깝게 그림
    '''
    sns.kdeplot(body_df['height'], bw=0.5)

     

    KDE 활용 예시

    # 히스토그램
    body_df.plot(kind='hist', y='Height', bins=15)
    
    
    # 히스토그램 위에 KDE 곡선이 그려짐
    sns.distplot(body_df['Height'], bins=15)  
    
    
    # 박스 플롯 : 통계 요약본 느낌
    body_df.plot(kind='box', y='Height')  
    
    
    # 바이올린 플롯 : 분포 전체를 볼 수 있음.
    sns.violinplot(y=body_df['Height']) 
    
    
    # 키와 몸무게의 연관성 → 산점도
    body_df.plot(kind='scatter', x='Height', y='Weight')
    # 175cm 70kg 학생들이 많이 분포함.
    # 키가 클수록 몸무게가 많이 나가는 경향이 있음.
    
    
    # 등고선 : 높낮이 표현
    sns.kdeplot(body_df['Height'], body_df['Weight']) 
    # x축 : 키에 대한 KDE
    # y축 : 몸무게에 대한 KDE
    # 3차원으로 생성, 간격이 멀수록 평평, 가까울수록 가파름.

    LM Plot

    sns.lmplot(data=body_df, x='Height', y='Weight')
    
    '''
    ◆ 회귀선(regression line) : 흩어져 있는 점들을 하나로 표현
    키 175cm인 학생은 몸무게 72kg정도 될 것 같다
    키와 몸무게의 연관성이 매우 뚜렷하지 않아서 모든 점들이 이 선을 다 지나가지 않음.
    '''

    pip install --upgrade numpy  # numpy 버전 업그레이드
    pip install --upgrade seaborn  # seaborn 버전 업그레이드
    → 둘 다 최신버전으로 업데이트해서 호환성 문제 발생하지 않도록 하면 오류 해결 가능

    카테고리별 시각화

    # box
    sns.catplot(data=laptops_df, x='os', y='price', kind='box')
    
    # strip
    sns.catplot(data=laptops_df, x='os', y='price', kind='strip')
    
    # hue : 색 (브랜드에 따라 색을 다르게 해줌)
    sns.catplot(data=laptops_df, x='os', y='price', kind='strip', hue='processor_brand')
    
    # swarm
    sns.catplot(data=laptops_df, x='os', y='price', kind='swarm', hue='processor_brand')
    
    # x축의 os 순서 바꾸기 (order 지정)
    sns.catplot(data=laptops_df, x='os', y='price', kind='swarm', hue='processor_brand', 
                order=['mac', 'linux', 'window'])
       

    3. 통계 기본 상식

    평균값과 중간값

    평균값(Mean) 중간값(Median)
    데이터들의 합 / 데이터 개수
    잘못된 데이터, 이상값의 영향을 크게 받음.
    주어진 값들을 크기순으로 정렬하였을 때 가장 중앙에 위치하는 값
    • 홀수 개수 : 가운데
    • 짝수 개수 : 가운데 2개의 평균 
    잘못된 데이터, 이상값의 영향을 덜 받음.

     

    Q1, Q3구하기

    Q1 Q3
    Q1이 몇 번 인덱스에 있는 값인지 구하기 : (8−1)∗0.25
    · 특정 퍼센트 지점 인덱스 : (데이터 개수 - 1) x 숫자
    (인덱스가 0부터 시작하니까)
    Q3이 몇 번 인덱스인지 구하기 : (8−1)∗0.75

    만약 인덱스가 1.75인 경우 :
    15(인덱스 1) 20(인덱스2) 사이의 0.75(4분의 3)
    15 * (1-0.75) + 20 * 0.75
    만약 인덱스가 5.25인 경우 :
    57(인덱스 1) 63(인덱스2) 사이의 0.25(4분의 1)
    57 * (1-0.25) + 63 * 0.25

     

    이상값 구하기

    IQR(Interquartile Range) = Q3 - Q1
    아래로 1.5 IQR 더 떨어져 있거나, Q3 지점에서 위로 1.5 IQR 더 떨어져 있는 값

    ex. Q3(58.5) - Q1(18.75) = 39.75 (-40.875와 118.125 사이의 바깥에 있는 값이 이상값)


    # 평균값
    
    import math
    
    list = [5, 48, 17, 62, 33, 18, 22]
    
    mean = sum(list) / len(list)
    print(mean)
    # 중앙값
    
    import math
    
    list = [5, 48, 17, 62, 33, 18, 22]
    
    A = (len(list) - 1) / 2
    
    if len(list) % 2 == 0:  # 짝수
        B = (list[math.floor(A)] + list[math.ceil(A)]) / 2
        print(B)
    else :  # 홀수
        C = list[math.floor(A)]
        print(C)
    list = [5, 48, 17, 62, 33, 18, 22]
    s_list = sorted(list)
    # [5, 17, 18, 22, 33, 48, 62]
    
    '''
    데이터 개수 : len(list)  # 7
    특정 지점 인덱스 : (len(list)-1) * 숫자
    '''
    
    # Q1과 Q3
    index_Q1 = (len(s_list)-1) * 0.25  # 1.5
    Q1 = s_list[1] * (1-0.25) + s_list[2] * 0.25  # 17.25
    
    index_Q3 = (len(s_list)-1) * 0.75  # 4.5
    Q3 = s_list[4] * (1-0.75) + s_list[5] * 0.75  # 44.25
    
    
    # 이상값
    IQR = Q3 - Q1  # 27.0
    '''
    (Q1 - 1.5 * IQR) <= num <= (Q3 + 1.5 * IQR)
    -23.25 <= num <= 84.75
    '''
    
    outlier = []
    
    # 이상값을 찾는 코드
    for num in s_list:
        if not (Q1 - 1.5 * IQR) <= num <= (Q3 + 1.5 * IQR):
            outlier.append(num)
    
    # 이상값이 있을 때만 출력
    if outlier:
        print("이상값은 {}입니다.".format(outlier))
    else:
        print("이상값이 없습니다.")
        
    '''
    이상값이 없습니다.
    '''
    '''
    같은 리스트에서 100, 13000을 추가
    '''
    
    list = [5, 48, 17, 62, 33, 18, 22, 100, 13000]
    s_list = sorted(list)
    # [5, 17, 18, 22, 33, 48, 62]
    
    '''
    데이터 개수 : len(list)  # 7
    특정 지점 인덱스 : (len(list)-1) * 숫자
    '''
    
    # Q1과 Q3
    index_Q1 = (len(s_list)-1) * 0.25  # 1.5
    Q1 = s_list[1] * (1-0.25) + s_list[2] * 0.25  # 17.25
    
    index_Q3 = (len(s_list)-1) * 0.75  # 4.5
    Q3 = s_list[4] * (1-0.75) + s_list[5] * 0.75  # 44.25
    
    
    # 이상값
    IQR = Q3 - Q1  # 27.0
    '''
    (Q1 - 1.5 * IQR) <= num <= (Q3 + 1.5 * IQR)
    -23.25 <= num <= 84.75
    '''
    
    outlier = []
    
    # 이상값을 찾는 코드
    for num in s_list:
        if not (Q1 - 1.5 * IQR) <= num <= (Q3 + 1.5 * IQR):
            outlier.append(num)
    
    # 이상값이 있을 때만 출력
    if outlier:
        print("이상값은 {}입니다.".format(outlier))
    else:
        print("이상값이 없습니다.")
    
    '''
    이상값은 [100, 13000]입니다.
    '''

    상관 계수 (Correlation Coefficient)

    데이터에서 두 변수가 얼마나 연관성이 있는지 보여주는 값

    Pearson 상관 계수

    0 x와 y는 연관이 없다
    1 x와 y는 확실한 연관이 있다 
    -1 x와 y는 확실한 연관(x가 커질수록 y가 작아짐)이 있다

     

    상관계수 시각화

    # 숫자 데이터 사이의 상관 계수
    df.corr() 
    
    # 히트맵 (상관계수의 시각화)
    sns.heatmap(df.corr())
    
    # annot은 숫자 표기되게끔 함
    sns.heatmap(df.corr(), annot=True)

    4. Exploratory Data Analysis

    탐색적 데이터 분석 (EDA)

    Exploratory Data Analysis
    데이터셋을 다양한 관점에서 살펴보고 탐색하면서 인사이트를 찾는 것
    ex.
    각 row는 무엇을 의미하는가
    각 column은 무엇을 의미하는가
    각 column은 어떤 분포를 보이는가
    두 column은 어떤 연관성이 있는가

    설문조사 결과 EDA
    기본정보 파악 : 참여인원, 연령대, 성별, 최종 학력, 가족관계, 관심사 등
    시각적인 방법, 통계적인 방법


    기본 정보 파악하기

    # 기본 정보가 있는 column
    basic_info = df.iloc[:, 140:]
    basic_info.head()
    basic_info.describe()
    basic_info['Gender'].value_counts()
    basic_info['Handedness'].value_counts()
    basic_info['Education'].value_counts()
    
    # 나이 분포
    sns.violinplot(data=basic_info, y='age')
    # 10대~20대후반이 많음.
    
    # 성별에 따른 나이분포
    sns.violinplot(data=basic_info, x='Gender', y='Age')
    
    # 성별에 따른 나이분포와 왼손/오른손잡이 유무
    sns.violinplot(data=basic_info, x='Gender', y='Age', hue='Handedness')
    
    # 키와 몸무게의 연관성 & 히스토그램 (jointplot)
    sns.jointplot(data=basic_info, x='Height', y='Weight')

    상관 관계 분석 (Correlation Analysis)

    '''
    좋아하면 5점, 안 좋아하면 1점
    음악 관련된 부분만 추출
    처음부터 19번째 열까지 음악과 관련됨
    '''
    
    # 데이터 추출
    music = df.iloc[:, :19]
    music.head()
    
    
    # 히트맵 그리기
    sns.heatmap(music.corr())
    
    '''
    연한색 = 연관성 ↑
    진한색 = 연관성 ↓
    
    오페라와 힙합 : 검정색
    오페라를 좋아하는 사람이 힙합을 덜 좋아할 것 같음.
    
    오페라와 클래식 : 주황색
    오페라를 좋아하는 사람이 클래식을 좋아할 것 같음.
    
    팝, 힙합, 테크노 장르들이 댄스와 큰 연관성이 있음.
    '''
    
    # 상관관계 중 나이에 관한 것만 출력해서 정렬
    df.corr()['Age'].sort_values(ascending=False)
    # -> 나이와 상관관계가 높은 것과 낮은 것을 확인할 수 있음

    import pandas as pd
    
    # 모든 행과 열을 표시하도록 설정
    pd.set_option('display.max_rows', None)  # 행
    pd.set_option('display.max_columns', None)  # 열
    
    # 설정 초기화
    pd.reset_option('display.max_rows')  # 행
    pd.reset_option('display.max_columns')  # 열
    # 특정 column이 몇 번째 인덱스에 있는지 알고 싶으면 
    df.columns.get_loc(' ')
    # 데이터프레임의 모든 열 목록 출력
    df.columns  
    # type : pandas.core.indexes.base.Index
    
    # 모든 열 이름을 리스트로 만들어서 출력
    df.columns.tolist()
    # type : list
    # --> 중간에 생략된 부분 있어서 리스트로 출력하니까 보임

    %matplotlib inline
    import pandas as pd
    import seaborn as sns
    
    df = pd.read_csv(r'C:\Users\airyt\Downloads/young_survey.csv')
    
    # 1부터 18 인덱스에 해당하는 열 출력
    df.iloc[:, 1:19].corr()['Getting up'].sort_values(ascending=False) 
    
    '''
    오류나는 이유
    df.iloc[:, 1:19] 부분은 1부터 18번째 열을 선택하는데, 
    이 범위에 'Getting up' 열이 포함되어 있지 않기 때문에 오류가 발생
    '''

    '''
    1. 데이터를 음악장르 + Getting up으로 추림
    2. Getting up과 관련된 부분만 상관관계 출력
    '''
    music_df = df.iloc[:, [i for i in range(19)] + [128]]
    music_df.corr()['Getting up'].sort_values(ascending=True)
    # --> 이렇게 굳이 할 필요 없음
    
    '''
    Getting up 열의 상관관계 분석 중 1번부터 18번째 열만 출력
    '''
    df.corr()['Getting up'][1:19].sort_values(ascending=True)

    주의할 점은 5점이 일찍 일어나기 힘듦, 1점이 일어나기 쉬움임.

    일찍 일어나는 사람들이 가장 좋아하는 음악 장르를 물어본다면,

    상관계수가 음수인 것중에 절대값이 큰 걸 골라야 함. (반대)

    # 특정 컬럼의 인덱스 값 가져오기 
    df.columns.get_loc()
    index = df.columns.get_loc('Getting up') # (대괄호 없이 이름만)
    print(index)  # 128
    
    '''
    get_loc()는 단일 열 이름에 대한 위치를 반환함.
    df.columns.get_loc(['Getting up', 'Dance']) ---> 에러 발생
    '''
    
    
    # 여러 컬럼의 인덱스 값 가져오기
    # get_loc() 안에 for 반복문으로 컬럼 하나씩만 가지고 와야됨
    
    columns_to_find = ['Getting up', 'Dance']
    indices = [df.columns.get_loc(c) for c in columns_to_find]
    print(indices)  # [128, 2]
    
    
    # 열 이름과 위치(인덱스) 동시에 출력
    print("열 위치")
    for col, index in zip(columns_to_find, indices):
        print(f'{col}:{index}')
    
    '''
    열 위치
    Branded clothing:135
    Healthy eating:75
    '''

    클러스터 분석(Cluster Analysis)

    클러스터 = 뭉쳐있는 무리
    데이터를 몇 가지 부류로 나누는 것 (ex. 학생들 = 이과, 문과, 예체능)

    # 사내 동아리 만드려고 하는데, 관심사 비슷한 사람들끼리 모을 것임
    df = pd.read_csv(r'C:\Users\airyt\Downloads/young_survey.csv')
    df.head()
    
    
    # 관심사 간 상관관계 구하기
    # 관심사가 있는 컬럼 : 'History'부터 'Pets'까지
    interests = df.loc[:, 'History':'Pets']
    c = interests.corr()
    
    
    # 역사 좋아하는 사람들만 따로 뽑아보기 (내림차순)
    c['History'].sort_values(ascending=False)
    # 정치, 지리, 법 등을 좋아하는 사람들과 묶을 수 있음
    # ---> 한 컬럼씩 일일히 다 하기 어려움
    
    
    # 연관성 있는 관심사끼리 묶어 놓은 것
    sns.clustermap(corr)
    # 묶여 있는 것들 : ex. 연극, 미술전시, 독서, 심리 등
    c = df.loc[:, 'Horror':'Action'].corr().sort_values(ascending=False)
    # 또는 c = df.loc[:, 'Horror':'Action'].sort_values(ascending=False).corr()
    
    sns.clustermap(c)  # 오류
    
    # sort_values가 데이터프레임 전체를 정렬하기 때문에 오류가 남.
    # 아래와 같은 방법을 고려할 수 있음.
    
    # 상관계수 행렬을 series로 변환하고 정렬
    sorted_corr = c.unstack.sorted_values(ascending=False)
    # 데이터프레임에서 빈 값 확인
    df.isna()
    
    # 또는
    df.isnull()
    
    # 'Horror'열에 빈값 있는지 확인하기
    df['Horror'].isna()

    타이타닉 EDA

     

    1. 타이타닉의 승객은 30대와 40대가 가장 많다.

    # 타이타닉의 승객은 30대와 40대가 가장 많다. (X)
    
    print(df[df['Age'] < 10]['Age'].count())  # 10세 미만의 승객 수 출력 : 62
    print(df[(10 <= df['Age']) & (df['Age'] < 20)]['Age'].count())  # 10대 승객 수 출력 : 102
    print(df[(20 <= df['Age']) & (df['Age'] < 30)]['Age'].count())  # 20대 승객 수 출력 : 220
    print(df[(30 <= df['Age']) & (df['Age'] < 40)]['Age'].count())  # 30대 승객 수 출력 : 167
    print(df[(40 <= df['Age']) & (df['Age'] < 50)]['Age'].count())  # 40대 승객 수 출력 : 89
    print(df[(50 <= df['Age']) & (df['Age'] < 60)]['Age'].count())  # 50대 승객 수 출력 : 48
    print(df[60 <= df['Age']]['Age'].count())  # 60세 이상 승객 수 출력 : 26
    # 히스토그램으로 보는 나이 분포
    df.plot(kind='hist', y='Age', bins=30)

     

    2. 가장 높은 요금을 낸 사람은 30대이다.

    # 가장 높은 요금을 낸 사람은 30대이다. (O)
    
    df[df['Fare'] == df['Fare'].max()]
    # 나이와 요금 사이를 산점도로 표현
    df.plot(kind='scatter', x='Age', y='Fare')

     

    3. 생존자가 사망자보다 더 많다.

    # 생존자가 사망자보다 더 많다. (X)
    # survived 컬럼에서 0과 1의 개수
    
    df['Survived'].value_counts()
    # 0 (사망): 549, 1:(생존) 342

     

    4. 1등실, 2등실, 3등실 중 가장 많은 사람이 탑승한 곳은 3등실이다.

    # 1등실, 2등실, 3등실 중 가장 많은 사람이 탑승한 곳은 3등실이다. (O)
    
    df['Pclass'].value_counts()
    '''
    3    491
    1    216
    2    184
    '''

     

    5. 가장 생존율이 높은 객실 등급은 1등실이다.

    # 가장 생존율이 높은 객실 등급은 1등실이다. (O)
    
    df.groupby('Pclass')['Survived'].value_counts()
    # ---> 2, 3등실은 사망이 더 많음.
    result = df.groupby(['Pclass', 'Survived']).size().unstack().fillna(0)
    result = result[[1, 0]]
    result['survival rate'] = result[1] / (result[0] + result[1]) * 100
    result
    
    # size() : 'Pclass'와 'Survived' 열을 기준으로 데이터를 그룹화한 후, 각 그룹의 크기를 계산하여 result에 저장
    # unstack() : 그 결과를 메서드로 표 형태로 변환함.
    # fillna() : 빈 값을 0으로 채움.
    # result[[1,0]] : 결과를 1과 0 순서로 재정렬

    # 객실 등급별 생존율 분포
    
    df.plot(kind='scatter', x='Pclass', y='Survived')
    # ---> 일반 산점도는 그림이 겹쳐서 나와서 KDE plot 이용
    
    '''
    sns.kdeplot(df['Pclass'], df['Survived']) 
    이렇게 쓰면 에러남.
    TypeError: kdeplot() takes from 0 to 1 positional arguments but 2 were given
    '''
    
    sns.kdeplot(x=df['Pclass'], y=df['Survived'])
    # ---> 1등급은 위쪽(생존율 높은 쪽)이 더 많이 나옴.

     

    6. 나이가 어릴수록 생존율이 높다.

    # 나이가 어릴수록 생존율이 높다. (X)
    # 상관관계 분석
    
    df.corr()
    # 생존 여부에 따른 나이 분포
    sns.violinplot(data=df, x="Survived", y="Age")

    좀 애매함

    생존한 사람들(1)의 나이분포와 사망한 사람의 나이분포(0)가 비슷함.

    유의미한 차이가 없어서 단정짓기 힘들다.

     

     

    7. 나이보다 성별이 생존율에 더 많은 영향을 미친다.

    # 나이보다 성별이 생존율에 더 많은 영향을 미친다. (O)
    
    result = df.groupby(['Sex', 'Survived']).size().unstack().fillna(0)
    result = result[[1, 0]]
    result['survival rate'] = (result[1] / (result[0] + result[1]))* 100
    result
    # 생존 여부에 따른 나이 및 성별 분포
    sns.stripplot(data=df, x="Survived", y="Age", hue="Sex")

    살아남은 사람들(Survived=1)의 분포 중 여성의 비율이 압도적으로 높음.


    5. 새로운 인사이트 발견하기

    새로운 값 계산하기

    새로운 컬럼 생성 후 그래프를 만들어서 인사이트 얻을 수도 있음.

     

    %matplotlib inline
    import pandas as pd
    df = pd.read_csv(r'C:\Users\airyt\Downloads/broadcast.csv', index_col=0)
    df
    df.plot()

     

    # 메이저 방송사들을 합찬 시청률
    # df['KBS'] + df['MBC'] + df['SBS'] + df['TV CHOSUN'] + df['JTBC'] + df['Channerl A'] + df['MBN']
    
    df.sum(axis='columns')
    df['Total'] = df.sum(axis='columns')
    df
    df.plot(y='Total')
    # TV 시청률이 해가 갈수록 떨어짐

     

    # 지상파 vs 종편 시청률 비교
    
    # 지상파 : df['KBS'] + df['MBC'] +df['SBS']
    # 종편 : df['TV CHOSUN'] + df['JTBC'] + df['Channel A'] + df['MBN']
    
    # 지상파와 종편을 각각 Group 1'과 'Group 2'으로 생성
    df['Group 1'] = df.loc[:, 'KBS':'SBS'].sum(axis='columns')  # 지상파
    df['Group 2'] = df.loc[:, 'TV CHOSUN':'MBN'].sum(axis='columns')  # 종편
    
    # 그래프 그리기
    df.plot(y=['Group 1', 'Group 2'])


    문자열 필터링

    # 모든 장르 파악 (중복제거)
    df['Genre'].unique()
    
    # 여기서 장르가 'Blues'인 앨범들만 추출
    df['Genre'] == 'Blues'
    
    # 장르에 'Blues'라는 단어가 포함된 앨범들이 추출
    df['Genre'].str.contains('Blues')
    
    # 장르에서 'Blues'가 앞에 있는 앨범들만 추출
    df[df['Genre'].str.startswith('Blues')]
    
    # 장르에서 'Blues'가 맨 뒤에 있는 앨범들만 추출
    df[df['Genre'].str.endswith('Blues')]
    
    이 데이터프레임에서 contains blues라는 컬럼
    포함하면 True, 안 그러면 False
    
    df['Contains Blues'] = df['Genre'].str.contains('Blues')
    df

    ### 1번 방법
    df['분류'][df['분류'] == False] = '일반'
    df['분류'][df['분류'] == True] = '대학'
    
    ### 2번 방법
    is_university = df['시설명'].str.contains('대학교')
    df.loc[is_university == True, '분류'] = '대학'
    df.loc[is_university == False, '분류'] = '일반'

    문자열 분리

    df = pd.read_csv(r'C:\Users\airyt\Downloads/parks.csv', index_col=0)
    
    df['소재지도로명주소']
    # 컬럼 출력
    
    df['소재지도로명주소'].str.split()
    '''
    ◆ 띄어쓰기 기반으로 단어를 나누어서 리스트를 생성
    
    관리번호
    29170-00001              [광주광역시, 북구, 대천로, 86]
    '''
    
    address = df['소재지도로명주소'].str.split(n=1, expand=True)
    df['관할구역'] = address[0]
    df
    '''
    ◆ n=숫자 --> 숫자번째 띄어쓰기만 가지고 나누어줌
    ◆ expand=True --> 나눈 것 기준으로 새로운 DF이 출력됨.
    
    관리번호
    29170-00001             [광주광역시, 북구 대천로 86]
    '''

    number = df['운영기관전화번호'].str.split(pat='-', n=2, expand=True)
    number = df['운영기관전화번호'].str.split('-', expand=True)
    
    # → 두 개 결과 똑같이 나옴.
    
    '''
    pat='' → 구분 기준 (문자)
    n=2 → 최대 2번 분리
    expand=True  → 결과가 DataFrame으로 보여짐
    '''

    카테고리로 분류

    # 브랜드가 아니라 노트북 제조한 국가별로 분류하고 싶음.
    
    brand_nation = {
    	'Deli' : 'U.S.',
    	'Apple' : 'U.S.',
    	'Acer' : 'Taiwan',
    	'HP' : 'U.S.',
    	'Lenovo' : 'China',
    	'Alienware' : 'U.S.',
    	'Microsoft' : 'U.S.',
    	'Asus' : 'Taiwan'
    }
    
    '''
    df['brand'].map(brand_nation)
    # map함수는 key와 item을 서로 바꿔줌.
    '''
    
    df['brand_nation'] = df['brand'].map(brand_nation)


    groupby

     

    # brand_nation 열을 기준으로 데이터프레임을 그룹화하여 nation_groups 객체에 저장
    nation_groups = df.groupby('brand_nation')
    
    # nation_groups의 타입을 출력 (pandas의 GroupBy 객체)
    type(nation_groups)
    
    # 각 그룹별로 데이터의 개수를 세어 반환
    nation_groups.count()
    
    # 각 그룹별로 'price' 열의 최대값을 반환
    nation_groups.max()
    
    # 각 그룹별로 'price' 열의 평균값을 반환
    nation_groups.mean()
    
    # 각 그룹별로 첫 번째 행을 반환
    nation_groups.first()
    
    # 각 그룹별로 마지막 행을 반환
    nation_groups.last()
    
    # 'price' 열에 대한 상자그림을 그림
    nation_groups.plot(kind='box', y='price')
    
    # 'price' 열에 대한 히스토그램을 그림
    nation_groups.plot(kind='hist', y='price')
    import pandas as pd
    
    data = {'성별': ['남', '여', '남', '여', '남'],
            '시험점수': [85, 95, 75, 90, 80]}
    
    df = pd.DataFrame(data)
    
    # groupby('그룹화컬럼')['집계컬럼'].통계함수()
    df.groupby('성별')['시험점수'].mean()
    
    # groupby('그룹화컬럼').통계함수()['집계컬럼']
    df.groupby('성별').mean()['시험점수']
    
    # [['그룹화컬럼','집계컬럼']].groupby('그룹화컬럼').통계함수()
    df[['시험점수', '성별']].groupby('성별').mean()
    
    '''
    1. df[['시험점수', '성별']]: 이 부분은 데이터프레임 df에서 '시험점수'와 '성별' 두 열을 선택함.
    2. .groupby('성별'): 선택한 열을 '성별' 기준으로 그룹화함. 이는 '성별'이 같은 행들을 하나의 그룹으로 묶음.
    3. .mean(): 그룹화된 결과에 대해 각 그룹의 평균을 계산함. 이 경우에는 '시험점수'의 평균을 계산함.
    
    '''

     


    데이터 합치기

    • inner join : 겹치는 것만
    • left outer join : 왼쪽 데이터프레임에 있는 것만
    • right outer join : 오른쪽 데이터프레임에 있는 것만
    • full outer join : 양쪽에 있는 모든 걸 합침
    # inner join
    pd.merge(price_df, quantity_df, on='Product')
    
    # left join
    pd.merge(price_df, quantity_df, on='Product', how='left')
    
    # right join
    pd.merge(price_df, quantity_df, on='Product', how='right')
    
    # full outer join
    pd.merge(price_df, quantity_df, on='Product', how='outer')

     

    728x90