본문 바로가기
LG 헬로비전 DX DATA SCHOOL/Python

Pandas 의 연산

by 황밤 2023. 8. 16.
728x90
반응형

2023/08/16

 

** Pandas 의 연산

 

1. 그룹화

  • 데이터를 어떤 기준에 따라서 여러 그룹으로 나누어서 관찰하는 것
  • 그룹화 한 후 집계, 변환, 필터링
  • 그룹화를 할 때는 groupby 를 이용하고 변환에는 apply를 이용
  • groupby 는 DataFrame의 함수 

 

  • 집계 함수
count : 누락 값을 제외한 데이터의 개수
size : 누락 값을 포함한 데이터의 개수
mean : 평균
std : 표준편차
min : 최소
max : 최대
quatile(q=값) : 백분위 수로 값은 0.0 ~ 1.0
sum : 합
var : 분산
sem : 평균의 표준편차
describe : 데이터의 간단한 집계
first : 첫 행
last : 마지막 행
nth : n 번째 행

 

  • 집계를 수행하고 난 후 DataFrame으로 리턴
  • 하나의 컬럼을 지정하면 Series로 리턴

 

  • 사용자 정의 함수 적용
agg(매핑 함수) : 여러 개의 함수를 적용하고자 하는 경우는 함수를 list로 전달하면 됩니다.
컬럼 마다 다른 함수를 적용하고자 할 때는 dict 를 이용({컬럼이름 : 함수, 컬럼이름:함수...})
transform : 그룹 별로 구분해서 각 우너소에 함수를 적용
filter
apply : 각 원소에 함수를 매핑

 

 

  • 멀티 이덱스 : 인데스 하나가 아니고 여러개 인 것
2 개 이상의 항목으로 그룹화를 하면 멀티 인덱스가 만들어 짐.
멀티 인덱스로 구성된 데이터에 직접 접근을 하고자 할 때는 lco[{첩번째 그룹 인덱스 , 두번째 그룹 인덱스

 

 

  • pivot_table : 집계를 위한 함수
첫번째 매개 변수로 Data Frame 을 설정
values 에는 연산을 수행할 컬럼을 나열
index 는 행 위치에 올 컬럼을 나열
columns 는 열 위치에 올 컬럼을 나열
margins 는 전체 데이터 집계출력 여부
aggfunc : 가상함수
fill_value : 는 na 일 때 값

 

  • class 와 sex 별로 age의 평균을 구하기
print(pd.pivot_table(df, index = 'sex', columns = 'class',values = "age", "aggfunc"='mean'))

 

 

 


 

 

 

 

 


 

2. 서울시 구별 CCTV 와 인구 데이터 사용

2.1) 데이터 수집

  • data.go.kr 등 서울시 데이터 포털
  • cctv.xlsx, pop.txt 활용

 

2.2) 필요 패키지 import

import pandas as pd
import numpy as np

#시각화 패키지

import matplotlib.pyplot as plt

#시각화 시 한글 출력을 위한 import
import platform
from matplotlib import font_manager, rc

 

 

 

2.3) 데이터 읽기

 

텍스트 파일을 읽을 때 확인

  • 구분 기호
  • 영문 과 숫자를 제외한 특수문자 포함 여부
  • 숫자 데이터의 경우 천 단위 구분 기호가 있는지 여부
  • 첫번째 행이 컬럼 이름인지 여부
  • 맨 처음 몇 행이나 마지막 몇 행이 주석이나 의미없는 데이터 인지
  • 전체 파일 사이즈가 어느 정도 되는지
#pop.txt 의 첫 두개의 열은 의미가 없으며, 한글을 포함, 구분 기호는 탭이며 천 단위 구분 기호가 존재 함.

pop = pd.read_csv("C:/Users/USER/Desktop/coding/0811/data/pop.txt", skiprows=2, delimiter="\t", thousands=",")
print(pop.head())
print(pop.info())

 

 

2.4) 컬럼 이름 변경

pandas 의 DataFrame 이나 Series의 편집 함수들은 대부분 데이터를 복제해서 작업한 후 리턴을 하는데 분석을 아주 길게 해야 되는 경우 이 방식은 메모리를 많이 사용합니다.
pandas 에서는 대다수의 편집 함수에 inplace 옵션을 제공하는데 이 값을 True로 설정하면 데이터를 복제하지 않고 원본에 작업을 수행합니다.
cctv.rename(columns={cctv.columns[0]:'구별'}, inplace=True)
pop.rename(columns={pop.columns[1]:'구별'}, inplace=True)

#cctv의 구이름에는 중간에 공백이 존재, pop은 구 이름에는 공백이 없음
gu = []
for x in cctv['구별'] :
    gu.append(x.replace(' ',''))
    
cctv['구별'] = gu

cctv
## 공백 제거 완료

 

 

 

 

2.5) 불 필요한 열과 행 정리

  • #열과 행을 제거하는 방법은 데이터에서 직접 제거 or 원하는 데이터만 추출

 

#pop 데이터에서 기간, 구별, 계, 남자, 여자 열만 필요
pop = pop[['기간', '구별', '계', '남자', '여자']]


#pop 데이터의 첫번째 행은 전체 데이터의 집계이므로, 불필요
pop.drop([0], inplace=True)


# 새로운 열을 추가 - 없는 열 이름에 데이터를 대입하면 됩니다.
pop['여성비율'] = pop['여자']/pop['계'] * 100

print(pop)

 

 

 

 

2.6) 2개의 데이터 합치기 - merge or join

df = pd.merge(cctv, pop, on='구별')
print(df)

 

 

 

 

2.7) 불필요한 컬럼 삭제

  • #2011년 이전, 2012년, 2013년, 2014년, 2015년, 2016년, 2017년, 기간 열을 삭제
#del을 이용 - pandas에서는 비추천

del df['2011년 이전']
del df['2012년']
del df['2013년']
del df['2014년']
del df['2015년']
del df['2016년']
del df['2017년']
del df['기간']

print(df)

 

 

 

2.8) 인덱스 재설정

  • Series 나 DataFrame은 행 단위 선택을 할 때 인덱스를 이용합니다. 
  • DataFrame을 만들 떼 Primary Key 역할을 하는 데이터가 존재한다면 인덱스로 설정하는 것이 좋다.
  • DataFrame에 인덱스를 잘 설정하면 DF 를 이용해서 pandas 의 차트를 만들 때 편리
df.set_index('구별', inplace=True)

print(df)

 

 

2.10) pandas 의 시각화 기능을 이용해서 소계에 대한 막대 그래프 그리기

df['소계'].plot(kind='barh', grid=True, figsize=(10,10))
plt.show()

 

 

2.11) pandas 정렬 하기

df['소계'].sort_values().plot(kind='barh', grid=True, figsize=(10,10))
plt.show()

 

 

2.12) 인구수 대비 cctv 개수를 막대 그래프로 출력

df['cctv 비율'] = df['소계']/df['계'] * 100
df['cctv 비율'].sort_values().plot(kind='barh', grid=True, figsize=(10,10))
plt.show()

 

 

2.13) 인구 수 와 cctv 개수 사이에 연관성이 있는지 확인 - 산점도가 유용

#matplotlib에서 제공하는 시각화를 활용

plt.figure(figsize=(6, 6))
plt.scatter(df['계'], df['소계'], s=50)
plt.xlabel('인구 수')
plt.ylabel('CCTV 개수')
plt.grid()
plt.show()
#산점도(산포도)를 그리는 경우에는 방향성과 그룹화 가능성을 확인합니다.

 

 

 

2.14) 추세선 만들기

#2개의 데이터간에 단항식을 계산하여 추세식 생성

#2개 항목의 단항식을 구하기
fp1 = np.polyfit(df['계'],df['소계'], 1)
f1 = np.poly1d(fp1)
print(f1)


#산점도와 단항식을 같이 출력

fx = np.linspace(100000, 700000, 100)

plt.figure(figsize=(6, 6))
plt.scatter(df['계'], df['소계'], s=50)
plt.plot(fx, f1(fx), ls='dashed', lw=3, color='g')
plt.xlabel('인구 수')
plt.ylabel('CCTV 개수')
plt.grid()
plt.show()

 

 

2.15) 그래프와 추세선의 차이 비교

#2개 항목의 단항식을 구하기
fp1 = np.polyfit(df['계'],df['소계'], 1)
f1 = np.poly1d(fp1)
print(f1)


#산점도와 단항식을 같이 출력

fx = np.linspace(100000, 700000, 100)

df['오차'] = np.abs(df['소계'] - f1(df['계']))

plt.figure(figsize=(14, 10))
plt.scatter(df['계'], df['소계'], c=df['오차'], s=50)
plt.plot(fx, f1(fx), ls='dashed', lw=3, color='g')

#좌표를 지정해서 레이블을 출력
for i in range(24):
    plt.text(df['계'][i] * 1.02, df['소계'][i] * 0.98, df.index[i], fontsize=12)

plt.xlabel('인구 수')
plt.ylabel('CCTV 개수')
plt.grid()
plt.show()

 

 


3. Choropleth(단계 구분도)

  • 지도에 색상이나 마커를 이용해서 크기를 표시하는 시각화 방법
  • 카토그램과 다른 점은 영역의 크기를 왜곡하지 않습니다.

3.1) 생성 방법

  • folium 이라는 패키지를 이용해서 지도를 출력한 후 choropleth 함수를 호출해서 geo_data 옵션에 아이디와 위도 및 경도를 가진 json 파일의 경로를 설정해주고 data에 출력할 DataFrame을 설정.
key_on에 json 파일에서 사용되는 id 컬럼을 지정

 

 

3.2) 한국 지리 정보

  • https://github.com/southkorea/southkorea-maps

 


 

 

4. 데이터 구조화

  • 인덱스 와 컬럼을 변경하는 작업
  • stack : 행을 컬럼으로 피벗시키는 작업
  • unstack : 컬럼을 행으로 피벗시키는 것

 

4.1) stack 함수

  • 컬럼을 인덱스로 변경해주는 함수
#멀티 인덱스로 사용할 데이터 생성
mul_index = pd.MultiIndex.from_tuples([('cust_1', '2015'), ('cust_1', '2016'), ('cust_2', '2015'),('cust_2', '2016')])


data = pd.DataFrame(data =np.arange(16).reshape(4, 4),
                   index=mul_index, columns=['prd_1', 'prd_2', 'prd_3', 'prd_4'],
                   dtype='int')

print(data)

#컬럼들이 하위 인덱스가 됨.
data_stacked = data.stack()

print(data_stacked)

 

  • dropna 옵션을 이용해서 

 

4.2) unstack

  • 인덱스를 컬럼으로 변경해주는 함수
  • 매개변수로 level을 받는데 level은 몇 번째 레벨의 인뎃르를 컬럼으로 변경할 지 설정
  • stack 을 할 때 dropna 속성을 False 로 설정한 경우는 완전한 복원이 이루어지지만 dropna를 True로 한 경우는 완전한 복우너이 이루어지지 않을 수 있습니다.
print(data_stacked.unstack(level=0))

#0레벨의 인덱스가 컬럼으로 변경됩니다.

 

 

4.3) 시계열 데이터의 재구조화

  • 시계열 데이터를 만들다 보면 년/월/일 등을 쪼개서 저장하는 경우가 있는데 데이터를 분석할 때 이렇게 쪼개져 있는 것이 불편한 경우가 많다.
  • 이런 경우 년,월,일을 합쳐서 하나의 컬럼으로 만들고 시간 순으로 나열해서 인덱스로 만드는 경우가 있습니다.

#시계열 인덱스 생성

periods = pd.PeriodIndex(year=data['year'], quarter=data['quarter'], name='data')
print(periods)
columns = pd.Index(['realgdp', 'infi', 'unemp'], name='item')

data = data.reindex(columns = columns)
print(data)
#인덱스에 날짜를 설정
data.index = periods.to_timestamp('D', 'end') # 쿼터의 마지막 날을 세부 데이터로 설정
print(data)
#날짜를 데이터로 사용
idata = data.stack().reset_index().rename(columns={0:'value'})
print(idata)

 

 

4.4) melt

  • pivot 과 반대되는 연산으로 여러 개의 컬럼을 하나의 컬럼으로 만들 때 사용
  • pandas.melt(DataFrame, id_vars=[남겨둘 컬럼 나열])
남겨둘 컬럼을 제외한 컬럼의 이름은 열(variable)의 값이 됩니다.
컬럼의 데이터들은 열(value)의 값이 됩니다.
  • 너무 많은 컬럼들이 존재할 때 컬럼의 개수를 줄이기 위해서 사용합니다.
data = pd.DataFrame({"cust_id":[1,2,3,4], "prod_id":["A", "B", "C", "D"],
                     "pch_cnt":[1,2,3,4], "pch_price":[100,200,300,400],
                    "pch_amt":[10,20,30,40]})

result = pd.melt(data, id_vars=["cust_id", "prod_id"])
print(result)

 

 

4.5) crosstab

  • 범주형 컬럼의 교차 분석(cross tabulations)에 사용
도수 분포표를 만들 때 사용
  • pandas.crosstab(행 방향에 사용할 컬럼의 이름 나열, 열 방향에 사용할 컬럼의 이름 나열, rownames = 행 이름, colnames=컬럼의 이름, margins=전체 합계 출력 여부, normalize = 정규화 여부 - 전체 합계에서의 비율)
data = pd.DataFrame({"id": ["id1", "id1", "id1", "id2", "id4", "id3"],
                    "fac_1":["a", "a", "b", "b", "c","c"],
                    "fac_2":["d", "d", "d", "c","c","c"]})
#fac_1, fac_2 의 빈도 분석
print(pd.crosstab(data['fac_1'], data['fac_2'], rownames=['사실'], colnames=['거짓']))

#id 별로 한번더 출력
print(pd.crosstab(data.id, [data['fac_1'], data['fac_2']]))

 

 

 


 

 

5. Catogram

  • 변량 비례도 또는 왜상 통계 지도로 번역하는데 지도의 면적을 왜곡해서 데이터를 표현하는 방식

 

 

 


*** 데이터 전처리(Pre Processing)

  • 데이터를 분석하기 전에 분석하기에 알맞은 데이터로 변환하는 작업
  • 소스에서 가공하는 경우도 있고 읽어낸 후 가공을 하기도 합니다.
데이터베이스에서 가져오는 경우 SQL 이나 함수를 이용해서 가공된 형태로 가져오기도 합니다.
  • 데이터 전처리는 하고자 하는 분석 방법에 따라서 데이터 형태에 따라서 달라집니다.
  • 데이터 형태를 구분할 때는 수치 데이터, 문자열 데이터, 범주형 데이터, 이미지 데이터로 분류를 합니다.

 

 

1. 수치 데이터

1.1) 단위 환산

  • 여러 나라에서 데이터를 수집하는 경우 나라마다 단위를 다르게 사용해서 직접 비교하기가 곤란한 경우가 있을 수 있습니다.
이런 경우 데이터를 동일한 단위로 환산을 해주어야 하고 데이터를 분석해서 결과를 만들 때 그 나라에 맞는 단위로 환산을 해서 결과를 만들어야 합니다.

 

1.2) 자료형 변환

  • 데이터의 자료형을 변경하고자 하는 경우 읽을 때는 dtypes 속성을 사용해서 자료형을 확인한 후 astype 함수를 이용해서 형 변환이 가능함
  • 데이터를 읽을 때 천 단위 구분 기호가 있는 경우 옵션 설정을 하지 않으면 문자열로 판단합니다.
None 이 있는 경우도 종종 문자열로 판단하는 경우가 있습니다.
#첫번째 행이 컬럼 이름이 아닌 경우 직접 컬럼 이름을 설정
df = pd.read_csv("./data/auto-mpg.csv", header = None)
df.columns = ['mpg', 'cylinders', 'displacement', 'horsepower', 'weight', 'acceleration', 'model year', 'origin', 'name']
print(df.dtypes)

df.info()
#horsepower은 마력으로 숫자 데이터이여 하는데, 자료형에는 object로 되어있음. 

#마력 데이터 내에 ?가 있음을 알 수 있음.

#print(df['horsepower'].sort_values()) #문자가 있는 경우 sort가 효과적임.

#?라는 값을 가진 데이터를 어떻게 처리할 것인가? 대체 값? 평균? 중앙값? 앞 혹은 뒤의 값? -> 제거로 결정

#? 값을 None 으로 설정하고 None 인 데이터를 제거
df['horsepower'].replace('?', np.nan, inplace=True)
df.dropna(subset=['horsepower'], axis=0, inplace=True)
df['horsepower'] = df['horsepower'].astype('float')
#origin 이라는 열은 1,2,3 이라는 값만 소유하고 있습니다.
#이 값은 실제로는 미국, 유럽, 일본을 의미하는 숫자임.
#분석을 할 때는 미국, 유럽, 일본으로 보여지는게 더 나을 수 있습니다.
#이런 경우는 새로운 컬럼을 추가해서 보여지도록 할 수 있고, 컬럼의 값을 변경할 수도 있음.
#범주형으로 변경해 두는 것이 분석 속도를 높이는데 도움이 됩니다. -> corr 같은 함수

df['origin'].replace({1:'미국', 2:'유럽', 3:'일본'}, inplace=True)

df['origin'] = df['origin'].astype('category') #범주형으로 변환
df.info()
반응형
LIST