Day20_SQL분석 33‐37_Python - bonniekwon0721/Dataanalytics-study GitHub Wiki
09/MAR/2024
-
User ID > 만들기 > 계산된 필드 > 이름: active user
COUNTD([User Id])
-
열 선반에 ‘EVENT TIME’ 넣어주고 > 삼각형 클릭 > 더보기 > 사용자 지정
- 세부 정보: 연도/월/일
-
데이터패널 > 매개변수 만들기 > 이름: p_날짜단위
- 데이터유형: 문자열
- 허용 가능한 값: 목록
값 표시 형식 day 일(daily) week 주(weekly) -
매개변수 표시
-
계산된 필드 만들기 > 이름: New Event Time
DATETRUNC([p_날짜단위], [Event Time], 'monday')- 열 선반에 만든 계산된 필드 ‘New Event Time’을 대체 적용하기.
-
삼각형 클릭 > 더보기 > 사용자 지정
- 세부 정보: 연도/월/일
-
이제 아까 만들어 두었던 ‘매개변수 표시’에서 ‘주(weekly)’를 클릭하면 날짜 형식을 바꿀 수 있다.
- 행 선반의 ‘집계(active user)’ > 퀵테이블 > ‘이동 평균’ 선택
- 기존 ‘집계(active user)’을 행 선반에 추가로 올리고 ‘이중축’ 선택 > 그리고 ‘축 동기화’ 하기
- 평균을 2 로 하느냐 3으로 하느냐에 따라서 ‘이동평균’은 변화됩니다.
- 여기서 ‘테이블 계산 편집’ > 이전’6’으로 바꾼다면 요일별로 장기적 추세를 볼 수 있다.
-
퀵테이블 만들기 > 이름: active user avg
CASE [p_날짜단위] WHEN 'week' THEN WINDOW_AVG([active user], -3, 0) WHEN 'day' THEN WINDOW_AVG([active user], -6, 0) END -
해당 시트를 추가하여 아까 추가로 올렸던 ‘집계(active user)’를 제거하고 열 선반에 > New Event Time을 올리고 > 요일로 보기 선택
- 추가로 분석에서 > 평균라인 > 패널 로 선택하여 그래프에 올리면
- 각 요일의 평균을 볼 수 있음.
- 행선반: Event Type
- 열선반: active user
- 표로 놓기
2-1) 먼저 cart 와 purchase간 고객 필터링
- 이름: user id(cart) -
IF [Event Type] = 'cart' THEN [User Id] END - 이름: user id(purchase) -
IF [Event Type] = 'purchase' THEN [User Id] END
2-2) 그 다음 cart와 purchase고객 카운팅
- 이름: active user(cart) -
COUNTD([user id(cart)]) - 이름: active user(purchase) -
COUNTD([user id(purchase)])
2-3) 비율 구하기
- 이름: conversion_cart -
[active user(cart)] / [active user] - 이름: conversion_purchase -
[active user(purchase)] / [active user]
그리고 레이블 서식을 백분율로 나타내보자.
-
계산된 필드 > 이름: conversion_cart_easy
COUNTD(IF [Event Type] = 'cart' THEN [User Id] END)/ COUNTD([User Id]) -
계산된 필드 > 이름: conversion_purcase_easy
/ COUNTD([User Id])COUNTD(IF[Event Type] = 'purchase' THEN [User Id] END)/ COUNTD([User Id])
- 이름: price_purchase
SUM(IF[Event Type] = 'purchase' THEN [Price] END)
- 이중축 만들기
- 사용자 지정
- 고정된 시작: 0 > 끝: 자동
- 이름: price_cart
SUM(IF[Event Type] = 'cart' THEN [Price] END)
- 이름: count_prd
COUNTD([Product Id])
- 이름: count_purchase
COUNT(IF [Event Type] = 'purchase' THEN [User Id] END)
- 이름: count_view
COUNT(IF [Event Type] = 'view' THEN [User Id] END)
- 이름: price_purchase
SUM(IF[Event Type] = 'purchase' THEN [Price] END)
- 이름: purchase/view
-
SUM(IF[Event Type] = 'purchase' THEN [Price] END)/ COUNT(IF [Event Type] = 'view' THEN [User Id] END)
-
- 이름: p_브랜드/카테고리
- 데이터 유형: 문자열
- 허용 가능한 값: 목록
- 값 Brand / 표시형식 브랜드
- 값 Category id / 표시형식 카테고리
-
이름: 브랜드/카테고리
CASE [p_브랜드/카테고리] WHEN 'Brand' THEN [Brand] WHEN 'Category Id' THEN [Category Id] END -
행선반의 값을 ‘브랜드/카테고리’로 변경
- 이름: INDEX
INDEX()
- 해당필드는 불연속형으로 생성
- 이름: p_페이지
-
데이터유형: 정수
-
허용가능한 값: 범위 먼저 생성하고 목록으로 전환해주기
- 최소값:20 / 최대값: 100 / 단위: 20
-
‘목록’으로 허용 가능한 값 전환하고 나서 ‘표시 형식’ 살짝 만져주기
20-40 40-60 60-80 80-100
-
-
이름: 페이지
//index = 1 //20 //0 [p_페이지]>=[INDEX] AND [INDEX] > [p_페이지] - 20
- 브랜드 열에 > 필터 클릭
- 정렬 기준: 필드
- 정렬순서: 내림차순
- 필드명 : price_purchase
- 필터
- 이름: 거래액>테이블
- 원본시트: 거래액
- 동작 실행 조건: 선택
- 대상 시트: 브랜드/카테고리별 상세
- 선택을 해제할 경우의 결과: 모든 값 표시
- 필터: 선택한 필드
- 원본 필드: YMD(New Event Time)
- <매개 변수.p_브랜드/카테고리>상세
- 해당 대시보드의 모든 테이블의 서식이 바뀐다.
- DB - DB적재, Relationship 이해, ERD
- SQL, Python - Adhoc Analysis, EDA, Data Transformation
- BI - Visualization, Reporting, Automation
| 분석 초기 세팅 | 데이터 탐구 | 대시보드 시각화 |
|---|---|---|
| 분석 환경 만들기 | Python EDA | BI Reporting |
| 데이터셋 관계 이해 | SQL Adhoc Query | 데이터로 제안/설득하기 |
| 데이터 컬럼 특성 이해 | 가설과 인사이트 | 조직 Data literacy 제고 |
-
Data 훑어보기 : with Pandas Data Frame
- Info, describe
- Null check
- Duplicates check
- Type check
-
Data 재구조화 : with Pandas Data Frame
- Groupby
- Picot_table
- Stack/Unstack
-
Cols Relation 파악 : with Visualization
- Heatmap Correlation
- Bar / Regplot / Histplot
- FacetGrid
- Jointplot
- 반복문으로 Subplots
import pandas as pd
from google.colab import drive
drive.mount("/content/drive")
pd.read_csv("/content/drive/MyDrive/Colab_Notebooks/Zerobase/Class_SQL_Analystics/data/Chapter04/HR-Employee-Attrition.csv")- Info()
- describe()
- NULL
- dtype
- 열이 뭐뭐가 있니
df = pd.read_csv("/content/drive/MyDrive/Colab_Notebooks/Zerobase/Class_SQL_Analystics/data/Chapter04/HR-Employee-Attrition.csv")
df.columns - 열이 몇개나 있니
len(df.columns) - 테이블 정보좀 다 가져와봐
df.info()# 중복값 여부 확인
print(len(df))
print(len(df.drop_duplicates())) # 중복된 값이 있으면 지워주고 보여줘
print(f"Duplicated Rows : {df.duplicated().sum()}") # 중복된 것이 있으면 세어줘df.describe() # 숫자 형식으로 된 값만 뽑아서 수치화해서 표현해주는 구문df.describe().T # 숫자 형식으로 된 값만 뽑아서 수치화해서 표현해주는 구문
# 컬럼과 로우를 바꿔서 보여줄래df.describe().round(0).T # 숫자 형식으로 된 값만 뽑아서 수치화해서 표현해주는 구문
# 컬럼과 로우를 바꿔서 보여줄래
# 소숫점은 지워줄래import numpy as np
np.mean([1,2,3,4,100]) # 1부너 100까지 다 더한뒤 2로 나눈 값.값은: 22.0 - 이상 수치의 영향을 많이 받았다.
np.median([1,2,3,4,100]) # 1부너 5까지의 중앙 값 # 중앙값은 이상 수치의 영향을 많이 받지 않는다.값은: 3.0 - 중앙값은 이상 수치의 영향을 많이 받지 않는다.
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html
: 하지만 문자형 데이터는 대부분 가져와서 describe 는 잘 안한다.
df.describe(include='all').round(0).T # 숫자 뿐 아니라 문자형의 형식도 포함한 값을 뽑아서 수치화해서 표현해주는 구문
# 컬럼과 로우를 바꿔서 보여줄래
# 소숫점은 지워줄래df.nunique() # 각 열당 유니크한 값이 몇개나 있니# Data info
# 우리만의 테이블을 만들어서 값을 확인해보자. (열을 뽑아서)
pd.DataFrame({
'Unique': df.nunique(),
'Null' : df.isna().sum(),
'Type' : df.dtypes
}
)pd.DataFrame().sort_values(by=”정렬 Column명”, ascending=TRUE or FALSE)
#오름차순은 ascending=TRUE
#내림차순은 ascending=FALSE# Data info
# 우리만의 테이블을 만들어서 값을 확인해보자. (열을 뽑아서)
pd.DataFrame({
'Unique': df.nunique(),
'Null' : df.isna().sum(),
'Type' : df.dtypes
}
).sort_values(by="Unique", ascending=False)pd.DataFrame().drop([Col1,Col2,...]
, axis = 1
, inplace=True)-
상세 설명
Inplace 파라미터는 DataFrame 에 생긴 변동사항을 원본 DataFrame 에 최종 반영할 것인지의 여부를 정하는 것으로, False가 디폴트
- TRUE → 해당 DataFrame 된 결과물이 저장 반영되는 것
- FALSE → DataFrame 변수 자체에는 저장되지 않으나, 결과물 조회만 하는 것
df.drop(['StandardHours','Over18','EmployeeCount'],axis=1,inplace=True)
df# 열의 갯수를 확인하면 지워졌는지 알 수 있다.
len(df.columns)# int / Object 이 섞여 있음. - object타입의 열만 보고싶어요.
df.select_dtypes(include='object')# int / Object 이 섞여 있음. - int64타입의 열만 보고싶어요.
df.select_dtypes(include='int64')**-pandas DataFrame**
- groupby
- pivot_table# 조직을 파악하기 위한 열을 가져오겠음.
tmp0 = df[['Department','EducationField','JobRole','JobLevel','Attrition']].copy()
#copy 를 해준다는 것은 원본 데이터프레임에 영향가지 않게 하기 위함.
tmp0.groupby('Department').size()tmp0.groupby('Department')['Department'].count()
#앞에 열 이름은 groupby 로 묶을 열 이름.
#뒤의 열 이름은 어떤 대상을 집계를 할지
#맨뒤는 aggregates (집계)tmp0.groupby('Department')['Department'].agg('count')- 위의 세개 구문은 다 같은 값을 가져온다.
size() / count() / agg(’count’)
tmp0.groupby(['Department','JobRole','JobLevel','EducationField']).size().sort_values(ascending=False).reset_index(name='Emp Count')-
상세 설명
이 코드는
tmp0이라는 데이터프레임을 여러 열('Department', 'JobRole', 'JobLevel', 'EducationField')에 따라 그룹화하고, 각 그룹에 속하는 행의 수를 계산한 후, 이 결과를 내림차순으로 정렬합니다. 그 다음, 이 결과를 새로운 데이터프레임으로 만들고, 행의 수를 나타내는 열을 'Emp Count'라고 이름지어 재설정합니다.코드의 구성을 분석해보겠습니다:
-
groupby(['Department','JobRole','JobLevel','EducationField']): 이 부분은 데이터를 'Department', 'JobRole', 'JobLevel', 'EducationField' 열에 따라 그룹화합니다. 이는 분석에서 특정 부서, 직무, 직급, 교육 분야별로 데이터를 나누고 싶을 때 유용합니다. -
size(): 각 그룹에 속하는 행의 수를 계산합니다. 이는 그룹별 직원 수를 알고 싶을 때 유용합니다. -
sort_values(ascending=False): 계산된 행의 수를 기준으로 데이터를 내림차순으로 정렬합니다. 이렇게 하면 가장 많은 직원이 있는 그룹부터 순서대로 볼 수 있습니다. -
reset_index(name='Emp Count'): 이 부분은 결과를 새로운 데이터프레임으로 만들고, 인덱스를 리셋합니다. 'name='Emp Count''는 그룹별 크기를 나타내는 열의 이름을 'Emp Count'로 설정합니다.
이 코드는 데이터를 면밀히 분석하고 싶을 때 매우 유용합니다. 예를 들어, 회사의 다양한 부서에서 특정 직무, 직급, 교육 분야별로 얼마나 많은 직원이 있는지 알고 싶을 때 이 코드를 사용할 수 있습니다.
비효율적인 부분을 개선할 수 있는지 여부는 데이터의 크기와 구조, 그리고 분석의 목적에 따라 다릅니다. 이 코드는 이미 상당히 최적화된 형태로 보입니다. 하지만, 매우 큰 데이터셋을 다룰 때는
groupby연산이 메모리를 많이 사용할 수 있으므로, 데이터를 처리하기 전에 필요하지 않은 열을 제거하는 등의 방법으로 데이터의 크기를 줄이는 것이 좋습니다. -
tmp1 = df[['Department','JobRole','JobLevel','Age','Attrition']].copy()
tmp1.groupby(['Department','JobRole'])['Age'].agg(['count','max','min'])
#groupby 로 다중의 집계함수를 사용 가능합니다.pt1 = pd.pivot_table(tmp1,
index=['Attrition','Department'],
columns='JobLevel',
values='Age',
aggfunc='count',
fill_value='')
pt1https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.unstack.html
pt2 = pd.pivot_table(tmp1,
index=['Attrition','Department','JobRole'],
columns='JobLevel',
values='Age',
aggfunc='count',
fill_value='')
pt2pt2.index# 0: 'Attrition', 1: 'Department', 2: 'JobRole'
pt2.index.names
# unstack은 컬럼쪽에 아래로 길게 있던걸 로우로 우측으로 길게 배열해주는 것.
# stack 은 반대로 로우로 우측으로 길게 있던걸 컬럼쪽에 아래로 길게 배열해주는 것.
pt2.unstack(level=0).stack(level=0)
st1 = pt2.unstack(level=0).stack(level=0)
st1.index
-
상세 설명
unstack()과stack()함수는 Pandas 데이터프레임의 구조를 변환하는 데 사용되며, 멀티레벨 인덱스(multi-level index) 또는 컬럼에 대해 작동합니다. 이 함수들은 데이터의 차원을 재구조화하는데 유용하게 사용됩니다.-
unstack()함수는 데이터프레임의 로우(행)를 컬럼(열)으로 "펼치는" 작업을 수행합니다. 즉, 데이터프레임이나 시리즈에서 멀티레벨 인덱스의 특정 레벨을 컬럼의 방향으로 회전시켜 재배치합니다. 이는 데이터를 넓게(wide format) 만들고 싶을 때 유용합니다. -
stack()함수는unstack()의 반대 작업을 수행합니다. 즉, 컬럼을 로우 방향으로 "쌓아서" 데이터프레임의 구조를 길게(long format) 만듭니다.
pt2.unstack(level=0).stack(level=0)코드는 두 가지 작업을 연속으로 수행합니다:- 먼저,
unstack(level=0)을 사용하여 데이터프레임pt2에서 가장 바깥쪽 레벨(0 레벨)의 인덱스를 컬럼으로 펼칩니다. 이로 인해 데이터 구조가 넓게 변형됩니다. - 그 다음,
stack(level=0)을 통해 방금 컬럼으로 변형된 구조를 다시 로우 방향으로 쌓아서 원래의 레벨로 돌려놓습니다.
이 과정을 거치면, 원본
pt2데이터프레임의 구조가 일시적으로 변형되었다가 다시 원래의 구조로 복귀합니다. 그러나, 이 과정을 통해 인덱스나 컬럼의 순서가 변경될 수 있으며, 데이터의 구조를 보다 명확히 이해하거나 특정 분석 목적에 맞게 조정하는데 도움을 줄 수 있습니다.이러한 작업은 데이터를 다양한 방식으로 재구조화하고자 할 때 유용하게 활용될 수 있으며, 특히 멀티레벨 인덱스를 가진 복잡한 데이터프레임을 다룰 때 매우 유용합니다.
-
| matplotlib | seaborn |
|---|---|
| https://matplotlib.org/stable/plot_types/index | https://seaborn.pydata.org/examples/index.html |
| Python 대표 시각화 Library | Matplotlib 기반의 Adds-on 성격의 Library |
| 기본적 그래프부터 통계, Image 처리까지 Documentation 과 Cheatsheet 참고! | 간단한 메서드로 다양한 통계 그래픽 |
# numeric데이터만 걸러서 상관관계를 분석하는 구문
df.corr()
# numeric데이터만 내가 직접 걸러서(int64) 상관관계를 분석하는 구문
df.select_dtypes(include='int64').corr()
import matplotlib.pyplot as plt
import seaborn as sns
cor_df = df.select_dtypes(include='int64').corr()
# 이렇게만 해도 heatmap은 나오나 알아보기 어렵다.
sns.heatmap(cor_df.corr())
# 사이즈를 넣어주고, 수치를 기입했어요.
plt.figure(figsize=(15,10))
sns.heatmap(cor_df.corr(),
annot=True)
plt.show()https://seaborn.pydata.org/generated/seaborn.color_palette.html
seaborn.heatmap(date
,annot=True #Heatmap에 숫자 표기
,fmt='.1f'. #Annotation Formatting - 소수점 표기
,linewidth=0.5 #Heatmap 사이 Line 두께
,cmap='Blues | YlGnBu | RdYlBu_r' #색상 Color map#heatmap 꾸미기
plt.figure(figsize=(15,10))
sns.heatmap(cor_df.corr(),
annot=True,
fmt='.1f',
linewidth=0.5,
cmap='RdYlBu_r')
plt.show()#heatmap 꾸미기
plt.figure(figsize=(15,10))
sns.heatmap(cor_df.corr(),
annot=True,
fmt='.1f',
linewidth=0.5,
cmap='YlGnBu')
#vmin=-1,vmax=1) #강제로 초대와 최소를 지정해주는 기능
plt.show()#heatmap 꾸미기
plt.figure(figsize=(15,10))
sns.heatmap(cor_df.corr(),
annot=True,
fmt='.1f',
linewidth=0.5,
cmap=sns.color_palette("Spectral", as_cmap=True))
plt.show()# 정수형 데이터만 가져와서 값을 합하자.
# 합을 하여 상관관계가 높을수록 숫자가 높다고 보면 됨.
df.select_dtypes(include='int64').corr().sum().sort_values(ascending=False)[:8]# 상관관계 높은 8개 애들만 리스트를 가져오세요
top8_cols = df.select_dtypes(include='int64').corr().sum().sort_values(ascending=False)[:8].index.tolist()
top8_colscor_df2 = df[top8_cols].corr()
sns.heatmap(cor_df2, annot=True, fmt='.1f', cmap='Blues')# 삼각형 Mask 씌워서 Heatmap 깔끔하게 그리기
import numpy as np
mask = np.zeros_like(cor_df2, dtype=bool)
mask[np.triu_indices_from(mask)] = True-
상세 설명
numpy.triu_indices_from(arr, k=0)[[source]](https://github.com/numpy/numpy/blob/v1.26.0/numpy/lib/twodim_base.py#L1119-L1183)
Return the indices for the upper-triangle of arr. See
[triu_indices](https://numpy.org/doc/stable/reference/generated/numpy.triu_indices.html#numpy.triu_indices)for full details.Parameters:
-
arr: ndarray, shape(N, N)
The indices will be valid for square arrays.
-
k: int, optionalDiagonal offset (see
[triu](https://numpy.org/doc/stable/reference/generated/numpy.triu.html#numpy.triu)for details).
Returns:
- triu_indices_from : tuple, shape(2) of ndarray, shape(N) Indices for the upper-triangle of arr.
-
sns.heatmap(cor_df2, annot=True, fmt='.1f', cmap='Blues', mask=mask)# Simple version - Matplotlib
plt.bar(df['JobLevel'], df['MonthlyIncome']) #plt.bar(x, y)
plt.show()# 조금 더 이쁘게 꾸며주기
plt.title('Simple Bar plot - Income by JobLevel')
plt.bar(df['JobLevel'], df['MonthlyIncome']) #plt.bar(x, y)
plt.xlabel('JobLevel')
plt.ylabel('MonthlyIncome')
plt.show()# 다른 그래프도 그려보자
plt.title('Simple Bar plot - TotalWorkingYears by JobLevel')
plt.bar(df['TotalWorkingYears'], df['MonthlyIncome']) #plt.bar(x, y)
plt.xlabel('TotalWorkingYears')
plt.ylabel('MonthlyIncome')
plt.show()https://seaborn.pydata.org/generated/seaborn.FacetGrid.html
# 부서별로 보면 좀 다르지 않을까?
facet = sns.FacetGrid(df, col='Department')
facet.map_dataframe(sns.barplot, x='TotalWorkingYears', y='MonthlyIncome')# 부서별로 보면 좀 다르지 않을까?
facet = sns.FacetGrid(df, col='Department', height=6)
facet.map_dataframe(sns.barplot, x='TotalWorkingYears', y='MonthlyIncome')
# 조금 보기 좋게 합시다.
facet = facet.fig.subplots_adjust(wspace=.4, hspace=.2)# 부서별로 보면 좀 다르지 않을까?
facet = sns.FacetGrid(df, col='Department', row='JobLevel', height=6) # 조금더 드릴다운 해서 row='JobLevel'까지 봅시다.
facet.map_dataframe(sns.barplot, x='TotalWorkingYears', y='MonthlyIncome')
# 조금 보기 좋게 합시다.
facet = facet.fig.subplots_adjust(wspace=.4, hspace=.2)요것은 다른 주제.
facet = sns.FacetGrid(df, col='JobLevel', row='Gender', height=3)
facet.map_dataframe(sns.barplot, x='TotalWorkingYears', y='MonthlyIncome')
plt.show()facet = sns.FacetGrid(df, col='JobLevel', row='Gender', height=3)
facet.map_dataframe(sns.barplot, x='YearsAtCompany', y='MonthlyIncome')
plt.show()Studied from 제로베이스 데이터스쿨