import sqlite3 # 가벼운 sqlite를 import
db_path = 'olist.sqlite\olist.sqlite'
db_connection = sqlite3.connect(db_path) # sql데이터가 저장된 위치를 변수에 저장
import pandas as pd # df생성과 전처리를 위해 pandas library 설치
def view_table(table, limit):
query = f"""
SELECT *
FROM {table}
LIMIT {limit}
"""
return pd.read_sql_query(query, db_connection) # 가장 중요한 함수
orders_per_day = """
SELECT
DATE(order_purchase_timestamp) AS day,
COUNT(*) AS order_count
FROM orders
GROUP BY day
"""
df = pd.read_sql_query(orders_per_day, db_connection)
df.head(10)
# pd.read_sql_query(실행할 sql쿼리 문자열, 연결 객체) : 쿼리 결과를 pandas dataframe으로 가져온다.
# """ """ 를 통해 sql 쿼리를 문자열로 바꿔준 이유는 pd.read_sql_query() 의 함수 구조 때문이다.
- matplotlib: python의 대표적인 시각화 라이브러리
- matplotlib.pyplot: 시각화를 위한 기본적인 플롯 제공(선, 막대, 히스토그램 등)
- matplotlib.dates: 시간 데이터와 관련된 기능을 제공. 날짜와 시간을 포함하는 데이터의 시각화를 돕는다.
고수들은 case when~ 처럼 반복 작업이 필요함 sql 쿼리를 python list comprehension을 통해 작성한다.
count_orders_per_hour = ',\n '.join([
f'COUNT(CASE WHEN hour = {i} THEN 1 END) AS "{i}"' \
for i in range(24)
])
orders_per_day_of_the_week_and_hour = f"""
WITH OrderDayHour AS (
{order_day_hour}
)
SELECT
day_of_week_name,
{count_orders_per_hour}
FROM OrderDayHour
GROUP BY day_of_week_int
ORDER BY day_of_week_int
"""
결과
ay_of_week_name,
COUNT(CASE WHEN hour = 0 THEN 1 END) AS "0",
COUNT(CASE WHEN hour = 1 THEN 1 END) AS "1",
COUNT(CASE WHEN hour = 2 THEN 1 END) AS "2",
COUNT(CASE WHEN hour = 3 THEN 1 END) AS "3",
COUNT(CASE WHEN hour = 4 THEN 1 END) AS "4",
COUNT(CASE WHEN hour = 5 THEN 1 END) AS "5",
COUNT(CASE WHEN hour = 6 THEN 1 END) AS "6",
COUNT(CASE WHEN hour = 7 THEN 1 END) AS "7",
COUNT(CASE WHEN hour = 8 THEN 1 END) AS "8",
COUNT(CASE WHEN hour = 9 THEN 1 END) AS "9",
COUNT(CASE WHEN hour = 10 THEN 1 END) AS "10",
COUNT(CASE WHEN hour = 11 THEN 1 END) AS "11",
COUNT(CASE WHEN hour = 12 THEN 1 END) AS "12",
COUNT(CASE WHEN hour = 13 THEN 1 END) AS "13",
COUNT(CASE WHEN hour = 14 THEN 1 END) AS "14",
COUNT(CASE WHEN hour = 15 THEN 1 END) AS "15",
COUNT(CASE WHEN hour = 16 THEN 1 END) AS "16",
COUNT(CASE WHEN hour = 17 THEN 1 END) AS "17",
COUNT(CASE WHEN hour = 18 THEN 1 END) AS "18",
COUNT(CASE WHEN hour = 19 THEN 1 END) AS "19",
COUNT(CASE WHEN hour = 20 THEN 1 END) AS "20",
COUNT(CASE WHEN hour = 21 THEN 1 END) AS "21",
COUNT(CASE WHEN hour = 22 THEN 1 END) AS "22",
COUNT(CASE WHEN hour = 23 THEN 1 END) AS "23"
FROM OrderDayHour
GROUP BY day_of_week_int
ORDER BY day_of_week_int
이렇게 나온 결과를
pd.read_sql_query(쿼리, 경로)
함수를 사용하여 dataframe을 생성한다.
한글을 사용하면 parsing error부터 시작해서 encoding error 심지어 length issue까지도 생긴다. 또한 시각화 시 폰트가 깨지는 경우가 다반사....... 그냥 utf-8, 영어 조합으로 맘 놓고 살자...
syntax:
plt.barh(y, width, height=0.8, left=None, align='center', kwargs)
y: 막대 그래프에서 Y축에 배치될 값입니다. 이는 일반적으로 카테고리를 나타내며, 리스트나 배열 형식으로 제공됩니다.
width: 막대의 길이, 즉 수평 방향으로의 값을 나타냅니다. 이는 카테고리별 수치 데이터로, 리스트나 배열 형식으로 제공됩니다.
height: 막대의 높이를 설정합니다. 기본값은 0.8입니다. 이 값은 막대가 얼마나 두꺼운지를 결정합니다.
left: 막대의 시작 위치를 설정합니다. 기본값은 None이며, 이는 막대가 Y축에서 시작함을 의미합니다.
align: 막대의 정렬 방법을 설정합니다. 기본값은 'center'이며, 막대가 Y축 값의 중앙에 정렬됩니다. 'edge'로 설정하면 막대가 Y축 값의 끝에서 시작합니다.
kwargs: 추가적인 그래프 속성(예: 색상, 투명도, 레이블 등)을 설정할 수 있습니다.
plt.figure(figsize=(10, 6))
plt.barh(top_cities['city'], top_cities['city_order_count'])
plt.xlabel('Number of orders')
plt.ylabel('City')
plt.title('Top 10 cities by number of orders')
plt.show()
plt.figure(figsize=(15, 6))
# Histogram for total product cost
plt.subplot(1, 2, 1)
plt.hist(df['product_cost'], bins=1000, color='#6c87a3')
plt.title('Product cost for orders < R$500')
plt.xlabel('Product cost (Brazilian reals)')
plt.ylabel('Frequency')
plt.xlim([0, 500])
# Histogram for total shipping cost
plt.subplot(1, 2, 2)
plt.hist(df['shipping_cost'], bins=800, color='#ad865f')
plt.title('Shipping cost for orders < R$80')
plt.xlabel('Shipping cost (Brazilian reals)')
plt.xlim([0, 80])
plt.show()
plt.subplot(1,2,1)
은 plt.figure(figesize=(15, 6))
으로 만들어 낸 영역을 1행 2열의 그리드로 나누고 1번째 구역에 그래프를 그리겠다는 뜻이다. histogram for total product cost 그래프가 1행1열 구역에 위치한다.
squarify : 트리맵(treemap) 시각화를 생성하기 위한 라이브러리. 데이터의 계층 구조나 비율을 직사각형으로 표현한다.
각 직사각형의 면적은 데이터 값에 비례한다. 대량의 데이터를 시각적으로 비교하거나 그룹을 표현하는 데 유용하다.
왜 튜터님이 sns 로 만들로 plt로 그린다고 말했는지 알 것 같다.
plt.figure(figsize=(12, 8))
order = categories_by_median_df['category'].tolist()
sns.boxplot(x='weight', y='category', data=df, order=order, showfliers=False)
plt.xlabel('Product weight (grams)')
plt.ylabel('Product category')
plt.title('Product weight by category (top 18 categories by sales)')
plt.xlim(-100, 26100)
plt.xticks(ticks=range(0, 30000, 2500))
plt.yticks(fontsize=14)
plt.show()
df.index = pd.to_datetime(df.index)
fig, ax = plt.subplots(figsize=(14, 8))
df.plot(ax=ax, marker='o', linestyle='-')
ax.set_xticks(df.index)
ax.set_xticklabels(df.index.strftime('%Y-%m'), rotation=90)
plt.title('Monthly sales for the selected categories')
plt.xlabel('Year-Month')
plt.ylabel('Monthly sales (Brazilian reals)')
plt.xticks(rotation=45)
plt.legend(title='Product category', title_fontsize=14, fontsize=14)
plt.grid(True)
plt.show()
라인 그래프를 그려 추세를 알아본 뒤, sales prediction에서 선형회귀가 나온다.
물류창고까지의 이동 시간은 모든 주에서 3일 전후로 비슷하지만 고객에게 닿는 시간이 엄청 상이하다.
계절의 영향도 받는가? ㅇㅇ
12월과 2월-3월. 12월은 크리스마스고, 2-3월은 19년도에 리우와 상파울루에서 계속되었던 우편국 파업 때문인 것 같다. 결제 시스템이 우편 시스템 송장 그거지 않았나?
상파울로와 리우데자누가 모두 이용고객이 많은데 왜 차이가 많이 나는지
평균 배달