Day21_SQL분석 38‐42_Python 시각화 SQL 전처리 - bonniekwon0721/Dataanalytics-study GitHub Wiki

10/MAR/2024


시각화를 통한 데이터 드릴다운 3 - Regplot

https://seaborn.pydata.org/generated/seaborn.regplot.html

sns.regplot(df, x='Age', y='MonthlyIncome')
  • 상세 설명

    양의 상관관계를 가지지만 보기가 복잡하다. 드릴다운해서 분석해봐야 할 듯

facet = sns.FacetGrid(df, col='Department', row='Gender')
facet = facet.map_dataframe(sns.regplot, x='Age', y='MonthlyIncome')
  • 상세 설명

    나누긴 했지만 여전히 보기가 불편하다. 그래프를 미세하게 조정해서 보기좋게 꾸미자

**facet = sns.FacetGrid(df, col='Department', row='Gender', hue='Attrition', height=5)
facet = facet.map_dataframe(sns.regplot, x='Age', y='MonthlyIncome')**
  • 상세 설명

    보기는 좋아졌으나, 범례가 없어 알아보기 아직 어렵다. 범례 등을 추가하자

facet = sns.FacetGrid(df, col='Department', row='Gender', hue='Attrition', height=5)
facet = facet.map_dataframe(sns.regplot, x='Age', y='MonthlyIncome')
facet = facet.add_legend() #범례 추가
# 조금만 더 예쁘게 꾸며주자
facet = sns.FacetGrid(df, col='Department', row='Gender', hue='Attrition', height=5,hue_order=['No','Yes'], palette={'Yes':'red', 'No': 'gray'})
facet = facet.map_dataframe(sns.regplot, x='Age', y='MonthlyIncome', fit_reg=False)
facet = facet.add_legend() #범례 추가

이번에는 다른 범례!

facet = sns.FacetGrid(df, col='EducationField', row='Gender', hue='Attrition', height=5, palette={'Yes':'red', 'No': 'gray'})
facet = facet.map_dataframe(sns.regplot, x='Age', y='MonthlyIncome')
facet = facet.add_legend() #범례 추가
facet = sns.FacetGrid(df, col='OverTime', row='Department', hue='Attrition', height=5, palette={'Yes':'red', 'No': 'gray'})
facet = facet.map_dataframe(sns.barplot, x='WorkLifeBalance', y='JobSatisfaction')
facet = facet.add_legend() #범례 추가

데이터 상관관계 한 눈에 파악하기 2 - Enumerate, Subplot ❤️ 💖

https://seaborn.pydata.org/generated/seaborn.histplot.html

sns.histplot(x=df['Age'])
sns.histplot(x=df['DistanceFromHome'])

나는 주요 컬럼들을 합쳐서 그래프를 보고싶어요

# i: index / col: column
# enumerate: 순서를 만들어줘야할 때 쓰곤 한다.

for i, col in enumerate(['Age', 'DistanceFromHome', 'JobStatisfaction', 'WorkLifeBalance', 'MonthlyIncome','YearsAtCompany']):
  print(i, col)
hist = ['Age', 'DistanceFromHome', 'JobSatisfaction', 'WorkLifeBalance', 'MonthlyIncome','YearsAtCompany']

plt.figure(figsize=(10,20))
for i ,col in enumerate(hist):
    axes = plt.subplot(6,3,i+1) #subplot 은 그야말로 sub
    sns.histplot(x=df[col], hue=df['Gender'])
plt.tight_layout()
plt.show()
  • 상세 설명

    이 코드는 hist 리스트에 포함된 변수들('Age', 'DistanceFromHome', 'JobSatisfaction', 'WorkLifeBalance', 'MonthlyIncome', 'YearsAtCompany')에 대해 히스토그램을 그리는 작업을 수행합니다. matplotlibseaborn 라이브러리를 사용하여, 각 변수별로 성별('Gender')에 따라 분포를 나타내는 히스토그램을 생성합니다.

    코드의 핵심적인 부분을 설명하겠습니다:

    • plt.figure(figsize=(10,20)): 그래프의 전체 크기를 가로 10인치, 세로 20인치로 설정합니다.
    • for i, col in enumerate(hist): hist 리스트에 있는 각 항목에 대해 반복을 수행합니다. enumerate 함수는 반복하는 동안 인덱스(i)와 항목(col)을 제공합니다.
    • plt.subplot(6,3,i+1): 6행 3열의 서브플롯 구조에서 i+1번째 위치에 서브플롯을 생성합니다. 여기서 주의할 점은, 실제로 여러분이 6개의 변수만 그릴 계획이라면 6행 3열 구조는 비효율적이며, 대신 6행 1열 또는 3행 2열 등을 사용하는 것이 적절합니다.
    • sns.histplot(x=df[col], hue=df['Gender']): seabornhistplot 함수를 사용하여 df[col]의 데이터에 대한 히스토그램을 그리고, hue=df['Gender'] 옵션으로 성별에 따른 색상 구분을 추가합니다. 이는 각 변수별로 남성과 여성의 분포를 비교할 수 있게 합니다.
    • plt.tight_layout(): 서브플롯들 사이에 적절한 간격을 자동으로 조정합니다. 이는 그래프가 겹치지 않고 깔끔하게 표시되도록 도와줍니다.
    • plt.show(): 최종적으로 생성된 피규어와 서브플롯들을 화면에 표시합니다.

    코드 수정 제안:

    • 서브플롯을 생성할 때, 실제로 필요한 행과 열의 수를 정확히 매칭시켜야 합니다. 이 코드의 경우 6개의 변수를 그래프로 표현하므로, 6행 1열(plt.subplot(6,1,i+1)) 또는 3행 2열(plt.subplot(3,2,i+1))이 더 적절할 수 있습니다.
    • 만약 실제로 6행 3열 구조를 사용하고자 한다면, 불필요한 서브플롯이 많이 생성되므로, 이 부분을 수정해야 합니다.

    위의 설명과 제안을 참고하여, 코드를 목적에 맞게 최적화할 수 있습니다.

데이터 상관관계 한 눈에 파악하기 3 - Jointplot

https://seaborn.pydata.org/generated/seaborn.jointplot.html

sns.jointplot(df, x='Age', y='YearsAtCompany', kind='reg')
sns.jointplot(df, x='Age', y='YearsAtCompany', hue='Gender')

seaborn.jointplot Parameters

sns.jointplot(data, x, y
,hue=[범례]
, marker=[Main data scatter 마커 표시]
, kind =[Scatter , kde, reg, hist  다른 종류의 그래프로 변경]
, marginal_ticks=True [Marginal Data에 y  추가]
, marginal_kws=[Marginal Data의 세부 디자인 조정])
  • 마커표시

    Default'" - Dot / 'o' - Circle / '+' - Plus / 'A' - Triangle 's' - Square / *** - Star / 'D' - Diamond

j = sns.jointplot(df, x='YearsAtCompany', y='Age'
                  , marker='+'
                  , marginal_ticks=True
                  , marginal_kws=dict(bins=30, rug=True))
j
j = sns.jointplot(df, x='YearsAtCompany', y='Age'
                  , marker='+'
                  , marginal_ticks=True
                  , marginal_kws=dict(bins=30, rug=True))
j.plot_joint(sns.kdeplot, color='r') # 등고선 그려주는 plot
j.plot_marginals(sns.rugplot, color='r', height=-.15, clip_on=False) 
# plot_marginals 그래프에 요소가 존재하는지 보여주는 빨간색 선.

MySQL Setting

이번 과정에서는 8.0.16버전을 쓴다. 그래야 나중에 Power BI 와 호환 가능

DBeaver Setting

Dbeaver 자주 쓰는 단축키

단축키 기능
CTRL + ENTER 현재 쿼리 실행
CTRL + \ 새 탭에서 현재 쿼리 실행
CTRL + / 현재 단일 행 주석 전환
CTRL + SHIFT + / 여러 행 주석 전환
CTRL + 1 새 SQL 편집기 열기
CTRL + SHIFT + + / 1 선택한 행을 위/아래로 이동 위/아래 쿼리
ALT + ^ /1 문 블록 일괄 선택
CTRL + SHIFT + F 선택한 SQL문 자동 정리

DBeaver DB Insert

  • 데이터베이스 연결(플러그 플러스 버튼) > MySQL
  • Databases > 우클릭 > Create New Databaes
    • 이름: HR / 타입: utf8
  • Data Transfer
    • 이때에 경로를 깨끗하게 잘 설정을 해주어야 추후 작업에서 불편하지가 않는다.
  • 데이터가 불러와지면 DDL > 테이블이 만들어진 코드가 보인다.
  • Data보면 예시로 200row데이터를 볼 수 있다.

SELECT

SQL 기본 골자

  • SELECT [Columns]
  • FROM [Source Table]
  • WHERE [Conditions]

Q) Data 전체 Columns 를 조회하기 위한 쿼리문은 어떻게 작성할 수 있을까요?

-- SELECT [Columns]
-- FROM [Schema]. [Table]

-- Dataset 전체 읽기

SELECT *
FROM hr.hr_employee_attrition hea
;

+Q) 만약 Column 의 순서를 Default 순서가 아닌 특정 순서로 조작하고 싶다면??

  • Ans) Column을 하나씩 입력!

Q) Data 특정 Columns 를 조회하기 위한 쿼리문은 어떻게 작성할 수 있을까요?

-- SELECT Col 1, Col 2, Col 3, Col4
-- FROM hr.hr_employee_attrition

SELECT EmployeeNumber, Attrition, Department, JobRole, JobLevel
FROM hr.hr employee attrition hea

+Q) hr_employee_attrition 데이터에서

Python Pandas DataFrame으로 동일하게 Column 4개를 추출하려면 ?

df[['Col_1', 'Col_2', 'Col_3', 'Col_4']]

* Count : 데이터의 Row 개수 카운트

-- SELECT COUNT ()
-- FROM hr.hr_employee_ attrition

SELECT count (*) AS count_row
FROM hr.hr_employee_attrition hea
;

아래 두 쿼리는 결과값이 다를까요?

SELECT count (*) AS count row
FROM hr.hr_employee_attrition hea
;
SELECT count (Department) AS count row
FROM hr.hr_employee_attrition hea
;
  • 결과값은 같습니다.

    DISTINCT 를 하지 않았기 때문

SELECT DISTINCT

데이터의 DISTINCT Row 개수 카운트

-- SELECT COUNT(DISTINCT[Col])

SELECT count (DISTINCT Department) AS count row
15 FROM hr.hr_employee_attrition hea
  • 만약 파이썬에다가 적용을 한다면

    ++ Python Pandas와 비슷한 메서드로는, drop_duplicates와 unique / nunique가 있습니다.

SELECT 실습

SQL작성

  • SQL 편집기 > 새 SQL 편집기
-- Dataset 전체 읽기
SELECT *
FROM HR.HR_Employee_Attrition hea 
;

-- 특정 column 만 읽기
SELECT EmployeeNumber , Attrition , Department , JobRole , JobLevel 
FROM  HR.HR_Employee_Attrition hea 
;

-- ROW 수 확인 : 1,470row
SELECT count(*) Headcount -- Headcount를 알리아스(별칭)로 지정한 것임.
FROM HR.HR_Employee_Attrition hea 
;

-- 직원 수 확인 : 1,470ea
SELECT COUNT(DISTINCT EmployeeNumber)
FROM HR.HR_Employee_Attrition hea
;

GROUP BY

SELECT [Cols], AGG([Col])
FROM [Source Table]
WHERE [Conditions]
GROUP BY [Cols]

-- * GROUP BY : 기준 Columns 으로 데이터의 집계값을 산출

* Department,JobRole, JobLevel 별 재직 인원수를 구해보자

SELECT Department, JobRole, JobLevel, count (*) AS hc
FROM hr.hr_employee _attrition hea
WHERE Attrition = 'No'
GROUP BY Department, JobRole, JobLevel
  • 상세설명

    (*)은 모든 값을 구하는 것.

Aggfunc Definition
COUNT() Row 개수 카운트
SUM() 합계
AVG() 평균
MIN() 최소값
MAX() 최대값

Q) Department, JobRole,Gender 별로 아래의 계산값을 산출해보자 (재직인원 기준)

  • 재직인원수
  • Age 최대값
  • Age 최소값
  • Age 평균값

Q) Department,JobLevel별로 아래의 계산값을 산출해보자 (재직인원 기준)

  • 재직인원수
  • TotalWorkingYears 평균 값
  • YearsAtCompany 평균 값
  • MonthlyIncome 최대값
  • Monthlyincome 최소값

ORDER BY

SELECT [Col 1], [Col 2], [Col 3], AGG([Col 4])
FROM [Source Table]
WHERE [Conditions]
GROUP BY [Col 1], [Col. 2], [Col 3]
ORDER BY [Col 1], [Col 2], [Col 3]
  • GROUP BY : 기준 Columns 으로 데이터의 집계값을 산출
  • ORDER BY : 기준 Columns 으로 데이터의 정렬 순서를 설정
  • 기본 정렬은 오름차순 (Ascending) 이며, 정렬을 원하는 Column 명 뒤에 정렬 타입을 명명
  • ASC : 오름차순 / DESC : 내림차순
ORDER BY [Col 1], [Col 2], [Col 3]
ORDER BY [Col 2], [Col 3], [Col 1]
ORDER BY [Col 1] DESC, [Col 2], [Col 3] DESC

* Department, JobRole, JobLevel 별 재직 인원수를 구한 뒤, Department, JobRole, JobLevel 순서대로 정렬하라

SELECT Department , JobRole, JobLevel  -- 2
			,count(*) AS hc
FROM hr.hr_employee_attrition hea  -- 1
WHERE Attrition = 'No' -- 3
GROUP BY Department, JobRole, JobLevel  -- 4
ORDER BY Department, JobRole, JobLevel  -- 5
  • 상세 설명

    나중에는 알리아스(별칭)을 Column(열) 에도 지정하여 부를 수 있음.

SELECT Department , JobRole, JobLevel 
			,count(*) AS hc
FROM hr.hr_employee_attrition hea 
WHERE Attrition = 'No'
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3

GROUP BY / ORDER BY 실습 1

/*GROUP BY*/
-- Department, JobRole, JobLevel 별 재직 인원수를 구해보자
SELECT Department, JobRole, JobLevel, COUNT(*) AS HC -- 2
FROM HR.HR_Employee_Attrition hea -- 1
WHERE Attrition = 'No'  -- 3 
GROUP BY Department, JobRole, JobLevel 
;
-- Python의 Pandas 같은 수식: df.GROUPby(['Department', 'JobRole', 'JobLevel']).countn()

-- 다양한 집계 함수 
-- Department, JobRole, Gender 별 제품인원수, Age의 최대/ 최소/ 평균값
SELECT Department, JobRole, Gender
	, COUNT(*) AS hc
	, MAX(Age) AS max_age
	, MIN(Age) AS min_age
	, AVG(Age) AS avg_age
FROM HR.HR_Employee_Attrition hea 
WHERE Attrition = 'No'
GROUP BY Department, JobRole, Gender 
;

GROUP BY / ORDER BY 실습 2

-- Department, JobLevel 별로 아래의 계산값을 산출해보자.
-- 재직인원수, TotalWorkingYears 평균값, YearAtCompany 평균값, MonthlyIncome 최대값, MonthlyIncome 최소값
SELECT Department, JobLevel
	, COUNT(*) AS `재직인원수`
	, ROUND(AVG(TotalWorkingYears),1) AS `TotalWorkingYears 평균값`
	, ROUND(AVG(YearsAtCompany),1) AS `YearAtCompany 평균값`
	, MAX(MonthlyIncome) AS `MonthlyIncome 최대값`
	, MIN(MonthlyIncome) AS `MonthlyIncome 최소값`
FROM HR.HR_Employee_Attrition hea 
WHERE Attrition = 'No'
GROUP BY Department, JobLevel
ORDER BY `YearAtCompany 평균값` DESC 
;

-- Alias 별명 다른 이름 
SELECT Department, JobLevel
	, COUNT(*) AS `재직인원수`
	, ROUND(AVG(TotalWorkingYears),1) AS `TotalWorkingYears 평균값`
	, ROUND(AVG(YearsAtCompany),1) AS `YearAtCompany 평균값`
	, MAX(MonthlyIncome) AS `MonthlyIncome 최대값`
	, MIN(MonthlyIncome) AS `MonthlyIncome 최소값`
FROM HR.HR_Employee_Attrition hea 
WHERE Attrition = 'No'
GROUP BY 1, 2
ORDER BY 6 DESC 
;

비교 연산자

비교 연산자 정의

| ~ 보다 크다 < | ~보다 작다 ≥ | ~ 보다 크거나 같다 ≤ | ~ 보다 작거나 같다 = | 같다 <> | 다르다 (크거나 작다) ≠ | 다르다

연산자 SELECT 절에서 사용하기

  • 1은 TRUE
  • 0은 FALSE

Q) 데이터셋에 여러 직원의 중복값이 있는지 확인해보려 한다.

전체 Row 개수와 EmployeeNumber의 Unique 개수가 맞는지 확인해보자

  1. 전체 Row 개수
(SELECT count (*) AS count row
FROM hr.hr employee attrition hea)
  1. EmployeeNumber의 Unique 개수
(SELECT count (DISTINCT EmployeeNumber) As count ho
FROM hr employee attrition hea)

본 데이터는 중복이 없으므로, 두 쿼리 다 1,470 Row 이다.

이것이 정답인지 한번에 알아보려면?

SELECT
	(SELECT count (*) AS count row
	FROM hr.hr employee attrition hea)
	=
	(SELECT count (DISTINCT EmployeeNumber) As count ho
	FROM hr employee attrition hea)
;

여기서 1 나오면 정답 0 나오면 거짓

Q) Sales 팀의 인원수를 확인해보자

SELECT count (*)
FROM hr.hr employee attrition hea
WHERE 1=1 -- 별 뜻은 없으나 뒤에 'AND'로 줄줄이 붙여줄 수 있다. 없는 애 취급 해도 된다. 
AND Department = 'Sales'

Q) 사내 주니어급 직원들을 대상으로 교육 프로그램을 진행하려 한다.

아래 조건에 맞는 대상자의 인원을 확인해보자

  1. 최소 1년 이상 재직 중
  2. 나이 30살 이하
  3. JobLevel이 2 이하
  4. HR 팀은 제외
SELECT count (*)
FROM hr.hr_employee_attrition hea
WHERE 1=1
AND YearsAtCompany >= 1
AND Attrition = 'NO'
AND Age <= 30
AND JobLevel <3
AND Department != 'Human Resources'

비교 연산자 실습

/*비교 연산자*/
-- True : 1, False : 0
SELECT 1=1;
SELECT 1=2;
SELECT 5>3;
SELECT 2!=1;
SELECT 10>=5;

-- 데이터셋 중복값이 있는지 없는지 확인 값이 1면 TRUE
SELECT 
	(SELECT count(*)
	FROM HR.HR_Employee_Attrition hea 
	)
	=
	(SELECT COUNT(DISTINCT EmployeeNumber) AS hc
	FROM HR.HR_Employee_Attrition hea) check_duplicated
;

-- 데이터셋 값 확
SELECT COUNT(*)
FROM ( SELECT DISTINCT *
		FROM HR.HR_Employee_Attrition hea 
		)hea2
		
		
		
-- 특정 팀의 인원수 파악
SELECT count(*)
FROM hr.HR_Employee_Attrition hea 
WHERE Department = 'Sales'
AND Attrition = 'No'
;

-- 뒤의 Quiz 풀기 전에 Department 에 무슨 Distinct 값이 있는지 확인하기.
SELECT DISTINCT Department
FROM HR.HR_Employee_Attrition hea; 

-- Quiz
-- 최소 1년 이상 재직 / 나이 30살 이하 / level 2 이하 / HR 팀 제외 만족하는 인원수 파악 
SELECT COUNT(*) 
FROM HR.HR_Employee_Attrition hea 
WHERE 1=1
AND Department != 'Human Resources'
AND YearsAtCompany >= 1
AND Age <= 30
AND Attrition = 'No'
AND JobLevel <= 2
;

논리 연산자

논리 연산자 정의
A AND B A와 B 모두 만족하는 경우 TRUE
A OR B A 또는 B 중 하나 이상 만족하는 경우 TRUE
NOT A A를 만족하지 않아야 TRUE
IN (A, B, C) 조건값이 A, B, C 중에 있으면 TRUE
BETWEEN A AND B A와 B 범위 내에 있으면 TRUE
LIKE A~~ 조건값이 A~~라는 규칙에 맞으면 TRUE

연산자 SELECT 절에서 사용하기

  • 1 은 True
  • 0은 False
SELECT 3 IN (0,1,2,3); -- 1
SELECT NOT (3 IN (0,1,2,3));  -- 0
SELECT 10 BETWEEN 1 AND 10;  -- 1
SELECT 5=5 AND 4=5;  -- 0
SELECT 5=5 OR 4=5;  -- 1
SELECT 'Apple' LIKE 'A%';  -- 1
SELECT 'Apple' LIKE 'A%e';  -- 1
SELECT 'Apple' LIKE 'A%p';  -- 0

Q) 사내 대리/과장급 직원들을 대상으로 교육 프로그램을 진행하려 한다.

아래 조건에 맞는 대상자의 인원을 확인해보자

  1. 최소 5년 이상 재직 중
  2. 나이 30살 이상 45살 이하
  3. JobLevel 3,4
  4. Sales, Research & Development 팀 소속 (HR 팀이 아니어야 함)
SELECT count (*)
FROM hr.hr_employee_attrition hea
WHERE 1=1
AND Attrition = 'No'
AND YearsAtCompany >= 5
AND Age BETWEEN 30 AND 45
AND JobLevel BETWEEN 3 AND 4
AND Department IN ('Sales','Research & Development')
;

Q) 아래 조건에 맞는 데이터를 Department와 JobLevel, Gender 별 인원수 그리고 평균 연령을 표기해주세요. 그리고 평균 연령을 내림차순으로 정렬해주세요

  1. 최소 5년 이상 재직 중
  2. 나이 30살 이상 45살 이하
  3. JobLevel 3,4
  4. Sales, Research & Development 팀 소속 (HR 팀이 아니어야 함)

++추가적으로 평균 연령은 정수로 0의 자리까지만 나오도록 조정하고 집계 컬럼은 각각HC와 Avg_age 라고 명명하여 나오도록 쿼리를 만들어주세요

논리 연산자 실습

/* 논리 연산자 */
SELECT 3 IN (0,1,2,3,4);
SELECT NOT(2 IN (0,1,2,3,4));
SELECT 100 NOT IN (0,1,2,3,4);

SELECT 5=5 AND 100=5;
SELECT 5=5 OR 100=5;

SELECT 'apple' LIKE 'a%';
SELECT 'apple' LIKE 'a%e';
SELECT 'apple' LIKE 'A%l';

-- 최소 5년 이상 재직 / 나이 30~45 / level 3,4 / Sales 혹은 R&D 소속 일 것
SELECT COUNT(*) 
FROM HR.HR_Employee_Attrition hea 
WHERE 1=1
AND Attrition = 'No'
AND YearsAtCompany >= 5
AND Age BETWEEN 30 AND 45
AND JobLevel IN (3, 4)
AND Department IN ('Sales', 'Research & Development')
-- AND Department <> 'Human Resources'
;

-- Department, joblevel, gender 별 인원수, 평균 연령 표기
-- 평균 연령으로 내림차순 (Round 0)
-- HC, avg_age 컬럼명 명
-- 최소 5년 이상 재직 / 나이 30~45 / level 3,4 / Sales 혹은 R&D 소속 일 것
SELECT Department, JobLevel, Gender
		, COUNT(*) HC
		, AVG(Age) Avg_Age
FROM HR.HR_Employee_Attrition hea
WHERE 1=1
AND Attrition = 'No'
AND YearsAtCompany >= 5
AND Age BETWEEN 30 AND 45
AND JobLevel IN (3, 4)
AND Department IN ('Sales', 'Research & Development')
GROUP BY 1, 2, 3
ORDER BY 5 DESC 
;

Studied from 제로베이스 데이터 스쿨

⚠️ **GitHub.com Fallback** ⚠️