[데이터분석] Pandas - DataFrame

2024. 8. 13. 16:22데이터 사이언스

DataFrame 생성

  • pd.DataFrame(data)
  1. List 사용
    date = [['초코파이', '몽쉘', '오예스'], ['오리온', '롯데', '해태'], [171, 170, 150], 5830, 5290, 4790]]
    df = pd.DataFrame(data)
    
    • +) index명, column명 설정
      date = [['초코파이', '몽쉘', '오예스'], ['오리온', '롯데', '해태'], [171, 170, 150], 5830, 5290, 4790]]
      df = pd.DataFrame(data, index='상품명', '제조사', '열량', '가격'], columns=['상품1', '상품2', '상품3'])
      


  2. Dictionary사용
    data = {'상품1' : ['초코파이', '오리온', 171, 5830], '상품2' : ['몽쉘', '롯데', 170, 5290], '상품3' : ['오예스', '해태', 150, 4790]}
    df = pd.DataFrame(data, index = ['상품명', '제조사', '열량', '가격'])
    
    • +) series 사용
      product_1 = pd.Series({'상품명' : '초코파이', '제조사':'오리온', '열량':171, '가격':5830})
      product_2 = pd.Series({'상품명' : '몽쉘', '제조사':'롯데', '열량':170, '가격':5290})
      product_3 = pd.Series({'상품명' : '오예스', '제조사':'해태', '열량':150, '가격':4790})
      df = pd.DataFrame({'상품1':product_1,'상품2':product_2,'상품3':product_3})
      
      



DataFrame 속성 확인

df.index # index명 확인
df.columns # column명 확인
df.shape # (행, 열) 크기 확인
df.head(n) # 데이터 상단 n개 행 출력
df.tail(n) # 데이터 하단 n개 행 출력
df.describe() # 칼럼(열)별 기술 통계량 출력
df.info # 칼럼(열)별 결측치, 데이터타입 등 출력
  • 결측치 확인 및 처리
# 결측치 확인
df.isnull()
df.isnull().sum() #column별 결측치 수 확인
df.isna()

df.notnull()
df.notna()

# 결측치 처리
df.fillna('Normal') # 결측치 'Normal'로 채우기
df.dropna() # 결측치 포함하고 있는 행 삭제

DataFrame 데이터 선택

# index로 지정
df.set_index('Name', inplace = True) # 'Name'열을 index로 지정

# Row 선택
df.loc['부산']
df.iloc[1]
df.loc[['부산', '울산']] # 2개 이상 행 선택 시, 대괄호 2개 필요

# column 선택
df['최고기온'] # 칼럼명 사용
df[df.columns[1]] # index 번호 사용

# 특정 데이터 선택(열과 행 선택)
df.loc['행 이름', '열 이름'] # loc 사용 (행 먼저)
df.iloc[행 번호, 열 번호] # iloc 사용 (행 먼저)
df['열 이름'][행 번호] # column명 사용 (열 먼저)
  • index로 지정
    • 이제 df.set_index('Name', inplace=True)를 실행하면, 'Name' 열이 인덱스로 설정되어 데이터프레임이 다음과 같이 변경
    • 'Name' 열이 인덱스가 되어 행을 식별하는 데 사용됨
    • inplace=True로 설정했기 때문에 df는 원본 데이터프레임을 직접 수정함

import pandas as pd
data = {
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['New York', 'Los Angeles', 'Chicago']
}

df = pd.DataFrame(data)
df.set_index('Name', inplace=True)

 

  • Column 선택
df['Speed'])  # Speed열 선택
df['Speed'].mean()  #포켓몬들의 Speed 평균값
df['Speed'].median()  # 포켓몬들의 Speed 중앙값

# 데이터 필터링
df[df['Type 1'] == 'Water'] # 'Type 1'이 'Water'인 데이터 선택
df[df['HP'] >= 50]  # 'HP'가 50 이상인 데이터 선택
df[(df['Type 1'] == 'Water') & (df['HP'] >= 50)]  # 'Type 1'이 'Water'이고 'HP'가 50 이상인 데이터 선택

 

  • 행과 열 선택
df.loc[:, ['Type 1', 'Type 2']] # 모든 포켓몬들의 Type 1, Type 2만 선택
df.iloc[2:11, 4] # index번호가 2부터 10까지인 포켓몬들의 HP(4) 선택
df.iloc[:10, 4:10] # 처음 10개 포켓몬들의 HP(4)부터 speed(9) 데이터 선택

DataFrame 데이터 수정

  • 추가/삭제
# 행 & 열 추가
df.loc['새로운 행 이름'] = 데이터 값
df.['새로운 열 이름'] = 데이터 값

# 행 & 열 삭제
df.drop('행 이름', axis = 0)
df.drop('열 이름', axis =1;
df.drop('Unnamed: 0', axis = 1, inplace = True) # 'Unnamed: 0'column 삭제
# inplace 옵션을 사용하여 수정사항 저장

# HP, Attack, Defense, Sp. Atk, Sp. Def, Speed 모두 더하여
# 'Total' 이름의 column 추가
df['Total'] = df['HP'] +df['Attack']+df['Defense']+df['Sp. Atk']+df['Sp. Def']+df['Speed']

# 위의 과정을 .sum() 함수 이용하여 시행 -> 데이터 선택 방법: iloc을 사용한 슬라이싱
df['Total2'] = df.iloc[:, 4:10].sum(axis=1)
  • 특정 데이터값을 다른 값으로 대체(replace 함수)
# 목표: Legendary 포켓몬 개수 세기

# 1단계) Legendary column에서 True는 1로, False는 0으로 바꾸기
# 원본 df에 수정사항 저장
df['Legendary'] = df['Legendary'].replace({True: 1, False: 0})

# 2단계) Legendary column 세로로 더하기
df['Legendary'].sum(axis=0)
  • 정렬
# index 기준
df.sort_index(ascending=True) # 오름차순
df.sort_index(ascending=False) # 내림차순

# 데이터 값 기준
df.sort_values('최고기온', ascending=False)

df.sort_values('Type 1') # 동일한 Type 1끼리 정렬
df.sort_values(['Type 1', 'HP']) # 동일한 Type 1끼리 정렬, 동일한 Type 1내에서는 HP 오름차순으로 정렬

DataFrame 데이터 연산

.sum() # 데이터의 합
.mean() # 데이터의 평균
.std(), var() # 데이터의 표준편차, 분산
.min(), max() # 데이터의 최솟값, 최댓값 반환
.idxmin(), idxmax() # 데이터의 최솟값, 최댓값이 위치한 인덱스 반환
.median() # 데이터의 중앙값 반환
.quantile(n) # n분위 수 반환

.apply() # 괄호 안 함수를 모든 데이터에 적용
  • 데이터 기술 통계량 확인
df.describe()
  • 수치 데이터에 함수 적용(apply 함수)
# 목표: HP가 50미만인 포켓몬들에게 HP+20, Attack+20, Defense+20 하기
# HP가 50 미만인 포켓몬들의 HP, Attack, Defense를 각각 20씩 증가시키는 함수
def increase_stats(row):
    if row['HP'] < 50:
        row['HP'] += 20
        row['Attack'] += 20
        row['Defense'] += 20
    return row

# apply를 사용하여 함수 적용
df.apply(increase_stats, axis=1)
  • axis 가 1이어야하는 이유?
    • df.apply(increase_stats, axis=1)에서 axis=1을 사용하는 이유는 각 행(row)에 대해 함수를 적용하기 위해서 이다.
    • ↔ 반면에 axis=0은 각 열(column)에 대해 함수를 적용할 때 사용된다.
      1. axis=0 (Default): 각 열(column)에 대해 함수를 적용
      2. axis=1: 각 행(row)에 대해 함수를 적용
    • 여기서 목표는 각 포켓몬의 HP, Attack, Defense 값을 수정하는 것이므로 각 행(row)을 기준으로 함수를 적용해야 하고 → 따라서 axis=1을 사용해야 한다.

import pandas as pd

data = {
    'Name': ['Pikachu', 'Bulbasaur', 'Charmander'],
    'HP': [35, 45, 39],
    'Attack': [55, 49, 52],
    'Defense': [40, 49, 43]
}

df = pd.DataFrame(data)

# increase_stats 함수는 각 포켓몬(row)의 HP가 50 미만인 경우,
# HP, Attack, Defense 값을 각각 20씩 증가시킴

def increase_stats(row):
    if row['HP'] < 50:
        row['HP'] += 20
        row['Attack'] += 20
        row['Defense'] += 20
    return row

# 각 행(row)에 대해 함수 적용
df = df.apply(increase_stats, axis=1)
print(df)
  • 만약 axis=0을 사용하면, 각 열(column)에 대해 함수를 적용하게 되므로 의도한 대로 작동하지 않는다.
df = df.apply(increase_stats, axis=0)
  • 이 경우, 함수가 열 단위로 작동하므로 각 열의 값들을 순회하게 됨 → 따라서 각 행에 대해 함수를 적용하기 위해서는 axis=1을 사용해야 함

 

  • 데이터 그룹화(groupby 함수)
# Type 1을 기준으로 데이터 그룹화, 그룹별 데이터 개수 확인
df.groupby('Type 1').count()

# Type 1을 기준으로 데이터 그룹화, 그룹별 데이터 값의 합 확인
df.groupby('Type 1').sum()