데이터 분석은 아래 5단계로 진행된다.
수업에서는 아래 단계에 맞추어 달 탐사 및 암석 샘플 데이터 분석을 수행했다.
데이터 분석 5단계
1. 문제 정의
- 현재 상황에 따른 문제점 파악
- 미래 개선될 점에 대해 분석 주제 정의
2. 데이터 수집
- 문제 정의에 따라서 분석에 필요한 데이터 선택
- 데이터 수집
3. 데이터 가공
- 확보한 데이터 관찰 및 기초 데이터 분석
- 분석에 필요한 데이터 컬럼 추가 및 가공
4. 데이터 분석
- 문제 정의를 반영한 데이터 분석
- 연관될 수 있는 다른 데이터의 수집, 연결 및 분석
5. 시각화 및 탐색
- 데이터 분석을 반영할 수 있는 시각화
- 문제 정의에 맞춘 해결방안 도출
데이터 조회
데이터 불러오기
# pandas 라이브러리를 Import하기
import pandas as pd
# 데이터 파일을 읽어오기
rock_samples = pd.read_csv("data/rocksamples.csv")
데이터 확인
# 데이터프레임 처음과 마지막 5개행 확인하기
rock_samples.head()

# 뒤에있는 5개
rock_samples.tail()

# 무작위로 아무거나
rock_samples.sample(5)

원활한 데이터 분석을 위해 데이터 사전 조사도 함께 진행한다.
개인적으로는 pristine과 regolith 컬럼의 의미를 확인하고자 사전 조사를 진행했다.
데이터 사전조사
pristine : 노출도, 깨끗한 정도(순수도), 재응용 되지않은 암석
regolith : 기반암을 덮고있는 흙, 먼지
데이터 프레임 정보 조회 및 요약 통계 확인
#rock_samples 데이터프레임 정보 확인하기
rock_samples.info()
총 2229의 데이터가 존재하며, 컬럼은 6개, 그리고 Subtype 컬럼에 결측치가 존재한다는 점을 확인할 수 있다.

# rock_samples 데이터프레임 수치 데이터의 요약 통계 확인
# 특이점 : *max 퍼센트 초과
rock_samples.describe()

데이터 프레임 분석
#rock_samples 데이터프레임 행수 확인
# 행과 열 (2229, 6)
# 행 수만 원한다면 [0]
rock_samples.shape[0]
#rock_samples 데이터프레임 열수 확인
rock_samples.shape[1]
#rock_samples 데이터 프레임의 인덱스 확인
rock_samples.index

#rock_samples 데이터프레임의 컬럼명 확인
rock_samples.columns

#rock_samples 데이터프레임 컬럼들의 데이터타입 확인
rock_samples.dtypes

각 컬럼별 결측치 확인
# 1단계 -> rock_samples 데이터프레임에 null값이 있는지 확인
rock_samples.isnull()
.isnull()함수로는 정확한 결측치 값 확인이 어렵기 때문에 아래에서 .isnull().sum()으로 결측치를 확인했다.

#결측치 갯수 확인. false:0, True:1
rock_samples.isnull().sum()

# 결측치가 있는 행을 출력
# rock_samples['Subtype'].isnull()
rock_samples[rock_samples['Subtype'].isnull()]

rock_samples['Type'].unique()

단위 변환
Weight (g) -> Weight(kg) 변환 작업을 수행한다.
# 1단계 -> 컬럼값변환 : rock_samples['Weight (g)'] -> rock_samples['Weight (kg)]
rock_samples['Weight (g)'] = rock_samples['Weight (g)'].apply(lambda x: x * 0.001)
rock_samples['Weight (g)']
# rename() 사용하기
# 새로운 변수명 말고 .inplace 를 사용해도 됨.
rock_samples = rock_samples.rename(columns={'Weight (g)' : 'Weight (kg)'})
아폴로 임무별 샘플 중량 총합
# rock_samples 데이터프레임의 'Mission' 컬럼을 기준으로 그룹으로 나눈다 -> groupby()
# 나누어진 그룹에서 'weight (kg)' 컬럼의 총합을 구한다 -> groupby('Mission')['weight (kg)].sum()
# 결국 아폴로 달탐사 임무별로 수집해온 암석 샘플 총중량을 구해서 새로운 변수에 할당한다. -> 이 변수는 시리즈이다.
sample_total_weight = rock_samples.groupby('Mission')['Weight (kg)'].sum()
weight_diff = missions['Sample weight (kg)'].diff()
# 아폴로 임무간의 수집해온 암석 샘플 총중량 차이를 나타내는 컬럼 'Weight diff'를 missions 데이터프레임에 추가
missions['Weight diff'] = weight_diff
missions
# 아폴로 11은 그 전 달탐사가 없어 NaN 값을 가지므로 결측치 0으로 채우기
# 원래 fillna를 사용하지 않지만, 아래의 경우애는 NaN값이 한 개 이므로 사용함.
missions.fillna(value=0, inplace=True)
missions
# 달탐사선 = 달모듈 + 명령모듈 --> 이 둘을 합쳐서 승무원 모듈
# 달 모듈의 이름, 중량 컬럼을 missions 데이터프레임에 추가
달모듈이름 = ['Eagle (LM-5)', 'Intrepid (LM-6)', 'Antares (LM-8)', 'Falcon (LM-10)', 'Orion (LM-11)', 'Challenger (LM-12)']
달모듈중량 = [15103, 15235, 15264, 16430, 16445, 16456]
missions['Lunar module (LM)'] = 달모듈이름
missions['LM mass (kg)'] = 달모듈중량
missions

# 아폴로 임무별로 달모듈 중량 차이를 구해서 새로운 컬럼 'LM mass diff'를 만들어서 missions 데이터프레임에 추가
LM_mass_diff = missions['LM mass (kg)'].diff()
missions['LM mass diff'] = LM_mass_diff

# 결측치가 있다면 0으로 채우기
missions['LM mass diff'].fillna(value=0, inplace=True)
# missions.fillna(value=0, inplace=True)
missions

#명령모듈의 이름, 중량 컬럼을 missionms 데이터프레임에 추가
명령모듈이름 = ['Columbia (CSM-107]', 'Yankee Clipper (CM-100])', 'Kitty Hawk (CM-110)', 'Endeavor (CM-112)', 'Casper (CM-113)', 'America (CM-114)']
명령모듈중량 = [5560, 5609, 5758, 5875, 5840, 5960]
missions['Command Module (CM)'] = 명령모듈이름
missions['CM Mass (kg)'] = 명령모듈중량
missions

#임무간 명령 모듈 중량 차이 구하기기
#아폴로 임무별로 명령모듈 중량 차이를 구해서 새로운 컬럼 'CM Mass diff'를 만들어 missions 데이터프레임에 추가
missions['CM mass diff'] = missions['CM Mass (kg)'].diff()
missions.fillna(value=0, inplace=True)
missions

# 승무원영역 = 달모듈 + 명령모듈
# 달 모듈과 명령모듈 중량을 합한 값을 'Total weight (kg)'라는 새로운 컬럼을 만들어 missions 데이터프레임에 추가
missions['Total weight (kg)'] = missions['LM mass (kg)'] + missions['CM Mass (kg)']
missions
# 승무원 영역을 나타내는 'Total weight (kg)'의 아폴로 임무별 중량 차이를 구하는 새로운 컬럼 'Total weight diff'를 missions 데이터프레임에 추가
missions['Total weight diff'] = missions['Total weight (kg)'].diff()
missions.fillna(value=0, inplace=True)
missions
실습 과정이 너무 길기 때문에 데이터 분석에 사용한 함수와 예시 코드로 다시 정리하면 아래와 같다.
데이터 탐색
.info(): 데이터프레임의 요약 정보
df.info()
.describe(): 숫자형 데이터 컬럼들의 요약 통계
df.describe()
.head(): 데이터프레임의 첫 5개 행
df.head()
.tail(): 데이터프레임의 마지막 5개 행
df.tail()
.sample(): 데이터프레임에서 지정된 개수만큼의 행을 무작위로 추출
df.sample(5)
.shape: 데이터프레임의 형태(행의 수, 열의 수)를 튜플로 반환
df.shape # (2229, 6)
.index: 데이터프레임의 인덱스 정보를 반환
df.index
.columns: 데이터프레임의 모든 컬럼명을 리스트 형태로 반환
df.columns = ['A', 'B']
.dtypes: 각 컬럼의 데이터 타입을 시리즈(Series) 형태로 반환
df.dtypes
.unique(): 특정 컬럼(Series)에 포함된 고유한 값들을 배열 형태로 반환
df['data'].unique()
.value_counts(): 특정 컬럼에 포함된 고유한 값들의 개수 반환
df['data'].value_counts()
type(): 변수의 자료형을 확인하는 파이썬 내장 함수
type(df)
데이터 정제
.loc[] : 이름이나 조건식을 사용하여 데이터의 특정 행/열 선택
low_samples = rock_samples.loc[(rock_samples['Weight (kg)'] >= 0.16) & (rock_samples['Pristine (%)'] <= 50)]
.isin() : 컬럼값이 특정 행에 포함이 되어있는지 boolean형태로 반환
low_samples['Type'].isin(['Basalt', 'Breccia'])
데이터 가공
.rename(): 데이터프레임의 컬럼명 변경
rock_samples = rock_samples.rename(columns={'Weight (g)':'Weight (kg)'})
.groupby(): 특정 컬럼값을 기준으로 데이터를 그룹으로 묶어 집계 연산(합, 평균 등)을 수행
'Mission' 컬럼을 기준으로 그룹화하여 'Weight (kg)'의 합계 반환
sample_total_weight = rock_samples.groupby('Mission')['Weight (kg)'].sum()
.size(): groupby와 함께 사용되며, 각 그룹의 크기(행의 개수)반환
rock_samples.groupby(['Type', 'Subtype']).size()
.sum(): 그룹화된 데이터나 시리즈의 합계를 반환
needed_samples_overview['Number of samples'].sum()
.mean(): 그룹화된 데이터나 시리즈의 평균 반환
artemis_mission['Estimated sample weight (kg)'].mean()
.diff(): 각 컬럼의 차이를 계산해주는 함수
missions['weight diff'] = missions['Sample weight (kg)'].diff()
.reset_index(): 인덱스로 설정된 데이터를 일반 컬럼으로 변환, 기본 정수 인덱스 생성
needed_samples_overview = needed_samples.groupby('Type')['Weight (kg)'].sum().reset_index()
sum(): 리스트나 시리즈의 모든 항목의 합을 구하는 파이썬 내장 함수
total_rocks = needed_samples_overview['Number of samples'].sum()
len(): 객체의 길이(항목의 수)를 반환하는 파이썬 내장 함수
crewed_pay_ratio = sum(missions['Crewed area : Payload']) / len(missions['Crewed area : Payload'])
결측치 처리
.isnull(): 데이터의 각 요소에 대해 결측치(NaN) 여부를 boolean 형태로 반환
rock_samples.isnull().sum()
.fillna(): 결측치를 지정된 값으로 변경
missions.fillna(value=0, inplace=True)
데이터 결합
.merge(): 데이터 프레임을 특정 컬럼을 기준으로 병합.
needed_samples_overview = pd.merge(needed_samples_overview, temp, on='Type')