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
'LG 헬로비전 DX DATA SCHOOL > Python' 카테고리의 다른 글
(Python)군집 분석 및 과일 이미지 군집 분석 실습 (0) | 2023.09.01 |
---|---|
회귀분석 (0) | 2023.08.30 |
Python 탐색적 시각화 (2) | 2023.08.11 |
Python 데이터 분석 Pandas 2 (0) | 2023.08.09 |
데이터 분석 Python (with numpy & pandas) (0) | 2023.08.07 |