BACK END/Python Library
[Pandas] pandas 정리2 - db, django
circle kim
2021. 3. 2. 15:23
local db
* db1.py
# sqlite : db 자료 -> DataFrame -> db
import sqlite3
sql = "create table if not exists test(product varchar(10), maker varchar(10), weight real, price integer)"
conn = sqlite3.connect(':memory:')
#conn = sqlite3.connect('mydb.db')
conn.execute(sql)
data = [('mouse', 'samsung', 12.5, 6000), ('keyboard', 'lg', 502.0, 86000)]
stmt = "insert into test values(?, ?, ?, ?)"
conn.executemany(stmt, data)
data1 = ('연필', '모나미', 3.5, 500)
conn.execute(stmt, data1)
conn.commit()
cursor = conn.execute("select * from test")
rows = cursor.fetchall()
for a in rows:
print(a)
print()
# DataFrame에 저장 1 - cursor.fetchall() 이용
import pandas as pd
#df1 = pd.DataFrame(rows, columns = ['product', 'maker', 'weight', 'price'])
print(*cursor.description)
df1 = pd.DataFrame(rows, columns = list(zip(*cursor.description))[0])
print(df1)
# DataFrame에 저장 2 - pd.read_sql() 이용
df2 = pd.read_sql("select * from test", conn)
print(df2)
print()
print(df2.to_html())
print()
# DataFrame의 자료를 DB로 저장
data = {
'irum':['신선해', '신기해', '신기한'],
'nai':[22, 25, 27]
}
frame = pd.DataFrame(data)
print(frame)
print()
conn = sqlite3.connect('test.db')
frame.to_sql('mytable', conn, if_exists = 'append', index = False)
df3 = pd.read_sql("select * from mytable", conn)
print(df3)
cursor.close()
conn.close()
교차 테이블(교차표) - 행과 열로 구성된 교차표로 결과(빈도수)를 요약
* cross_test
import pandas as pd
y_true = pd.Series([2, 0, 2, 2, 0, 1, 1, 2, 2, 0, 1, 2])
y_pred = pd.Series([0, 0, 2, 1, 0, 2, 1, 0, 2, 0, 2, 2])
result = pd.crosstab(y_true, y_pred, rownames=['True'], colnames=['Predicted'], margins=True)
print(result)
'''
Predicted 0 1 2 All
True
0 3 0 0 3
1 0 1 2 3
2 2 1 3 6
All 5 2 5 12
'''
# 인구통계 dataset 읽기
des = pd.read_csv('https://raw.githubusercontent.com/pykwon/python/master/testdata_utf8/descriptive.csv')
print(des.info())
# 5개 칼럼만 선택하여 data frame 생성
data = des[['resident','gender','age','level','pass']]
print(data[:5])
# 지역과 성별 칼럼 교차테이블
table = pd.crosstab(data.resident, data.gender)
print(table)
# 지역과 성별 칼럼 기준 - 학력수준 교차테이블
table = pd.crosstab([data.resident, data.gender], data.level)
print(table)
원격 DB 연동
* db2_remote.py
import MySQLdb
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rc('font', family='malgun gothic')
import csv
import ast
import sys
try:
with open('mariadb.txt', 'r') as f:
config = f.read()
except Exception as e:
print('read err :', e)
sys.exit()
config = ast.literal_eval(config)
print(config)
# {'host': '127.0.0.1', 'user': 'root', 'password': '123', 'database': 'test',
# 'port': 3306, 'charset': 'utf8', 'use_unicode': True}
try:
conn = MySQLdb.connect(**config)
cursor = conn.cursor()
sql = """
select jikwon_no, jikwon_name, jikwon_jik, buser_name, jikwon_gen, jikwon_pay
from jikwon inner join buser
on jikwon.buser_num = buser.buser_no
"""
cursor.execute(sql)
for (jikwon_no, jikwon_name, jikwon_jik, buser_name, jikwon_gen, jikwon_pay) in cursor:
print(jikwon_no, jikwon_name, jikwon_jik, buser_name, jikwon_gen, jikwon_pay)
# jikwon.csv 파일로 저장
with open('jikwon.csv', 'w', encoding='utf-8') as fw:
writer = csv.writer(fw)
for row in cursor:
writer.writerow(row)
print('저장성공')
# csv 파일 읽기 1
df1 = pd.read_csv('jikwon.csv', header=None, names = ('번호', '이름', '직급', '부서', '성별', '연봉'))
print(df1.head(3))
print(df1.shape) # (30, 6)
# csv 파일 읽기 2
df2 = pd.read_sql(sql, conn)
df2.columns = ('번호', '이름', '직급', '부서', '성별', '연봉')
print(df2.head(3))
'''
번호 이름 직급 부서 성별 연봉
0 1 홍길동 이사 총무부 남 9900
1 2 한송이 부장 영업부 여 8800
2 3 이순신 과장 영업부 남 7900
'''
print('건수 :', len(df2))
print('건수 :', df2['이름'].count()) # 건수 : 30
print()
print('직급별 인원 수 :\n', df2['직급'].value_counts())
print()
print('연봉 평균 :\n', df2.loc[:,'연봉'].sum() / len(df2))
print('연봉 평균 :\n', df2.loc[:,'연봉'].mean())
print()
print('연봉 요약 통계 :\n', df2.loc[:,'연봉'].describe())
print()
print('연봉이 8000이상 : \n', df2.loc[df2['연봉'] >= 8000])
print()
print('연봉이 5000이상인 영업부 : \n', df2.loc[(df2['연봉'] >= 5000) & (df2['부서'] == '영업부')])
print()
print('* crosstab')
ctab = pd.crosstab(df2['성별'], df2['직급'], margins=True)
print(ctab)
print()
print('* groupby')
print(df2.groupby(['성별', '직급'])['이름'].count())
print()
print('* pivot table')
print(df2.pivot_table(['연봉'], index=['성별'], columns=['직급'], aggfunc = np.mean))
print()
# 시각화 - pie 차트
# 직급별 연봉 평균
jik_ypay = df2.groupby(['직급'])['연봉'].mean()
print(jik_ypay, type(jik_ypay)) # Series
print(jik_ypay.index)
print(jik_ypay.values)
plt.pie(jik_ypay,
labels=jik_ypay.index,
labeldistance=0.5,
counterclock=False,
shadow=True,
explode=(0.2, 0, 0, 0.3, 0))
plt.show()
except Exception as e:
print('process err :', e)
finally:
cursor.close()
conn.close()
# DataFrame의 자료를 DB로 저장
data = {
'irum':['tom', 'james', 'john'],
'nai':[22, 25, 27]
}
frame = pd.DataFrame(data)
print(frame)
print()
# pip install sqlalchemy
# pip install pymysql
from sqlalchemy import create_engine
import pymysql # MySQL Connector using pymysql
pymysql.install_as_MySQLdb()
engine = create_engine("mysql+mysqldb://root:"+"123"+"@Localhost/test", encoding='utf-8')
conn = engine.connect()
# MySQL에 저장하기
# pandas의 to_sql 함수 사용 저장
frame.to_sql(name='mytable', con = engine, if_exists = 'append', index = False)
df3 = pd.read_sql("select * from mytable", conn)
print(df3)
Django
PyDev Django Project 생성
* Django - Create application - myjikwonapp
= django_use01
* settings
...
INSTALLED_APPS = [
...
'myjikwonapp',
]
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test', # DB명 : db는 미리 작성되어 있어야 함.
'USER': 'root', # 계정명
'PASSWORD': '123', # 계정 암호
'HOST': '127.0.0.1', # DB가 설치된 컴의 ip
'PORT': '3306', # DBMS의 port 번호
}
}
* anaconda prompt
cd C:\work\psou\django_use01
python manage.py inspectdb > aaa.py
* models
from django.db import models
# Create your models here.
class Jikwon(models.Model):
jikwon_no = models.IntegerField(primary_key=True)
jikwon_name = models.CharField(max_length=10)
buser_num = models.IntegerField()
jikwon_jik = models.CharField(max_length=10, blank=True, null=True)
jikwon_pay = models.IntegerField(blank=True, null=True)
jikwon_ibsail = models.DateField(blank=True, null=True)
jikwon_gen = models.CharField(max_length=4, blank=True, null=True)
jikwon_rating = models.CharField(max_length=3, blank=True, null=True)
class Meta:
managed = False
db_table = 'jikwon'
* Django - Create Migrations - myjikwonapp
* Django - Migrate
* urls
from django.contrib import admin
from django.urls import path
from myjikwonapp import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.MainFunc),
path('showdata', views.ShowFunc),
]
* views
from django.shortcuts import render
from myjikwonapp.models import Jikwon
import pandas as pd
import matplotlib.pyplot as plt
plt.rc('font', family='malgun gothic')
# Create your views here.
def MainFunc(request):
return render(request, 'main.html')
def ShowFunc(request):
#datas = Jikwon.objects.all() # jikwon table의 모든 데이터 조회
datas = Jikwon.objects.all().values() # dict type
#print(datas) # <QuerySet [{'jikwon_no': 1, 'jikwon_name': '홍길동', ...
pd.set_option('display.max_columns', 500) # width : 500
df = pd.DataFrame(datas)
df.columns = ['사번', '직원명','부서코드', '직급', '연봉', '입사일', '성별', '평점']
#print(df)
'''
사번 직원명 부서코드 직급 연봉 입사일 성별 평점
0 1 홍길동 10 이사 9900 2008-09-01 남 a
1 2 한송이 20 부장 8800 2010-01-03 여 b
2 3 이순신 20 과장 7900 2010-03-03 남 b
3 4 이미라 30 대리 4500 2014-01-04 여 b
4 5 이순라 20 사원 3000 2017-08-05 여 b
'''
# 부서별 급여 합/평균
buser_group = df['연봉'].groupby(df['부서코드'])
buser_group_detail = {'sum':buser_group.sum(), 'avg':buser_group.mean()}
#print(buser_group_detail)
'''
{'sum': 부서코드
10 37900
20 58900
30 37300
40 25050,
'avg': 부서코드
10 5414.285714
20 4908.333333
30 5328.571429
40 6262.500000
}
'''
# 차트를 이미지로 저장
bu_result = buser_group.agg(['sum', 'mean'])
bu_result.plot.bar()
#bu_result.plot(kind='bar')
plt.title("부서별 급여 합/평균")
fig = plt.gcf()
fig.savefig('django_use01/myjikwonapp/static/images/jik.png')
return render(request, 'show.html', {'msg':'직원정보', 'datas':df.to_html(), 'buser_group':buser_group_detail})
* main.html
<body>
<h2>메인</h2>
<a href="showdata">직원정보</a>
</body>
* show.html
<body>
<h2>{{msg}} (DB -> pandas 이용)</h2>
{% if datas %}
{{datas|safe}}
{% endif %}
<hr>
<h2>부서별 급여합</h2>
총무부 : {{buser_group.sum.10}}<br>
영업부 : {{buser_group.sum.20}}<br>
전산부 : {{buser_group.sum.30}}<br>
관리부 : {{buser_group.sum.40}}<br><br>
<h2>부서별 급여평균</h2>
총무부 : {{buser_group.avg.10}}<br>
영업부 : {{buser_group.avg.20}}<br>
전산부 : {{buser_group.avg.30}}<br>
관리부 : {{buser_group.avg.40}}<br><br>
<img alt="사진" src="/static/images/jik.png" title="차트 1-1">
</body>
* desc_stat
# 기술 통계
'''
기술통계(descriptive statistics)란 수집한 데이터의 특성을 표현하고 요약하는 통계 기법이다.
기술통계는 샘플(전체 자료일수도 있다)이 있으면, 그 자료들에 대해 수치적으로 요약정보를 표현하거나,
데이터 시각화를 한다.
즉, 자료의 특징을 파악하는 관점으로 보면 된다. 평균, 분산, 표준편차 등이 기술통계에 속한다.
'''
# 도수 분포표
import pandas as pd
frame = pd.read_csv('../testdata/ex_studentlist.csv')
print(frame.head(2))
print(frame.info())
'''
name sex age grade absence bloodtype height weight
0 김길동 남자 23 3 유 O 165.3 68.2
1 이미린 여자 22 2 무 AB 170.1 53.0
'''
print('나이\t:', frame['age'].mean())
print('나이\t:', frame['age'].var())
print('나이\t:', frame['age'].std())
print('혈액형\t:', frame['bloodtype'].unique())
print(frame.describe().T)
print()
# 혈액형별 인원수
data1 = frame.groupby(['bloodtype'])['bloodtype'].count()
print('혈액형별 인원수 : ', data1)
'''
혈액형별 인원수 : bloodtype
A 3
AB 3
B 4
O 5
'''
print()
data2 = pd.crosstab(index = frame['bloodtype'], columns = 'count')
print('혈액형별 인원수 : ', data2)
'''
혈액형별 인원수 : col_0 count
bloodtype
A 3
AB 3
B 4
O 5
'''
print()
# 성별, 혈액형별 인원수
data3 = pd.crosstab(index = frame['bloodtype'], columns = frame['sex'])
data3 = pd.crosstab(index = frame['bloodtype'], columns = frame['sex'], margins=True) # 소계
data3.columns = ['남', '여', '행합']
data3.index = ['A', 'AB', 'B', 'O', '열합']
print('성별, 혈액형별 인원수 : ', data3)
'''
성별, 혈액형별 인원수 : 남 여 행합
A 1 2 3
AB 2 1 3
B 3 1 4
O 2 3 5
열합 8 7 15
'''
print()
print(data3/data3.loc['열합','행합'])
print()
'''
남 여 행합
A 0.066667 0.133333 0.200000
AB 0.133333 0.066667 0.200000
B 0.200000 0.066667 0.266667
O 0.133333 0.200000 0.333333
열합 0.533333 0.466667 1.000000
'''