1. Pandas

1) Pandas DataFrame and Operations

# pandas 라이브러리를 불러옵니다. pd를 약칭으로 사용합니다.
import pandas as pd
import numpy as np

DataFrame은 2차원 테이블이고, 테이블의 한 줄(행/열)을 Series라고 합니다.

Series의 모임이 곧, DataFrame이 됩니다.

# 12x4 행렬에 1부터 36까지의 숫자를 원소를 가지고, index는 0부터 시작하고, coulmns은 순서대로 X1, X2, X3, X4로 하는 DataFrame 생성
np.random.seed(42)
df = pd.DataFrame(data=np.random.randn(10, 3),
                 columns=['X1', 'X2', 'X3'],
                 index=pd.date_range('2024-01-01', '2024-01-10'))
df

# dataframe index
df.index

>>> DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
                   '2024-01-05', '2024-01-06', '2024-01-07', '2024-01-08',
                   '2024-01-09', '2024-01-10'],
                  dtype='datetime64[ns]', freq='D')
# dataframe columns
df.columns

>>> Index(['X1', 'X2', 'X3'], dtype='object')
# dataframe values
df.values

>>> array([[ 0.49671415, -0.1382643 ,  0.64768854],
           [ 1.52302986, -0.23415337, -0.23413696],
           [ 1.57921282,  0.76743473, -0.46947439],
           [ 0.54256004, -0.46341769, -0.46572975],
           [ 0.24196227, -1.91328024, -1.72491783],
           [-0.56228753, -1.01283112,  0.31424733],
           [-0.90802408, -1.4123037 ,  1.46564877],
           [-0.2257763 ,  0.0675282 , -1.42474819],
           [-0.54438272,  0.11092259, -1.15099358],
           [ 0.37569802, -0.60063869, -0.29169375]])
# 특정 column을 가져오기
df['X2']

>>> 2024-01-01   -0.138264
    2024-01-02   -0.234153
    2024-01-03    0.767435
    2024-01-04   -0.463418
    2024-01-05   -1.913280
    2024-01-06   -1.012831
    2024-01-07   -1.412304
    2024-01-08    0.067528
    2024-01-09    0.110923
    2024-01-10   -0.600639
	Freq: D, Name: X2, dtype: float64
# X1 column에 2 더하기
df['X1'] ** 2

>>> 2024-01-01    0.246725
    2024-01-02    2.319620
    2024-01-03    2.493913
    2024-01-04    0.294371
    2024-01-05    0.058546
    2024-01-06    0.316167
    2024-01-07    0.824508
    2024-01-08    0.050975
    2024-01-09    0.296353
    2024-01-10    0.141149
    Freq: D, Name: X1, dtype: float64

2.1) Dataframe 기초 method

# dataframe의 맨 위 다섯줄을 보여주는 head()
df.head(3)

# dataframe에 대한 전체적인 요약정보를 보여줍니다. index, columns, null/not-null/dtype/memory usage가 표시됩니다.
df.info()

>>> <class 'pandas.core.frame.DataFrame'>
    DatetimeIndex: 10 entries, 2024-01-01 to 2024-01-10
    Freq: D
    Data columns (total 3 columns):
     #   Column  Non-Null Count  Dtype  
    ---  ------  --------------  -----  
     0   X1      10 non-null     float64
     1   X2      10 non-null     float64
     2   X3      10 non-null     float64
    dtypes: float64(3)
    memory usage: 320.0 bytes
# dataframe에 대한 전체적인 통계정보를 보여줍니다.
df.describe()

# X2 column를 기준으로 내림차순 정렬
df.sort_values(by='X2', ascending=False)

2.2) 여러 DataFrame 합치기

SQL Join(inner, left, outer)

<=> pd.merge

df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 
                    'B': ['B0', 'B1', 'B2', 'B3'],
                    'C': ['C0', 'C1', 'C2', 'C3'],
                    'D': ['D0', 'D1', 'D2', 'D3']},
                   index=[0, 1, 2, 3])

df2 = pd.DataFrame({'A': ['A2', 'A3', 'A4', 'A5'],
                    'E': ['B4', 'B5', 'B6', 'B7'],
                    'F': ['C4', 'C5', 'C6', 'C7'],
                    'G': ['D4', 'D5', 'D6', 'D7']},
                   index=[0, 1, 2, 3])

df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
                    'B': ['B8', 'B9', 'B10', 'B11'],
                    'C': ['C8', 'C9', 'C10', 'C11'],
                    'D': ['D8', 'D9', 'D10', 'D11']},
                   index=[8, 9, 10, 11])
# SQL과 같이 join operation을 사용할 수 있다.
# inner : 교집합.
pd.merge(df1, df2, how='inner', on='A')

# left join
# left : 왼쪽 데이터를 기준으로 있는 것들만 합치고, 없는건 결측치로.
pd.merge(df1, df2, how='left', on="A")
#pd.merge(df1, df2, how='outer', on="A")

# 그냥 합치기 (concatenation)
pd.concat([df1, df2, df3])

2.3) DataFrame으로 데이터 불러오기

Source : https://www.kaggle.com/c/titanic/data

# train.csv 파일 불러오기
titanic = pd.read_csv('./data/train.csv')
titanic

# Q1. 생존자 비율
titanic.Survived.value_counts(normalize=True)

>>> 0    0.616162
    1    0.383838
    Name: Survived, dtype: float64
# Q2. 여성 승객들의 평균 나이.
female = titanic[titanic.Sex == 'female']  # boolean mask(=filter) --> fancy indexing
np.mean(female.Age)  # female.Age.mean()

# DataFrame의 특정 조건에 해당하는 데이터를 뽑는 방법.
# .loc[row에 대한 조건, col에 대한 조건]
female_age = titanic.loc[titanic.Sex == 'female', 'Age']
np.mean(female_age)

>>> 1      38.0
    2      26.0
    3      35.0
    8      27.0
    9      14.0
           ... 
    880    25.0
    882    22.0
    885    39.0
    887    19.0
    888     NaN
    Name: Age, Length: 314, dtype: float64
# Q3. 남성 승객들중에서 가장 높은 fare.
male_fare = titanic.loc[titanic.Sex == 'male', 'Fare']
np.max(male_fare)

>>> 0       7.2500
    4       8.0500
    5       8.4583
    6      51.8625
    7      21.0750
            ...   
    883    10.5000
    884     7.0500
    886    13.0000
    889    30.0000
    890     7.7500
    Name: Fare, Length: 577, dtype: float64
# Q4. 이름에 Mrs.가 포함된 사람 찾기 (= 기혼 여성이 몇명인지 찾기)
titanic[titanic.Name.str.contains('Mrs')]

# Q5. 결측치(NaN)가 포함된 모든 데이터 찾기
titanic[titanic.isnull().any(axis=1)]

# Q6. 해당 column의 결측치가 50% 이상인 column을 찾아서 drop하기
drop_cols = titanic.columns[titanic.isnull().mean() >= 0.5] # 각 column별 결측치 비율이 50% 이상인 column.
titanic = titanic.drop(columns=drop_cols) # overwrite
titanic

2.4) Pivot Table을 이용하여 데이터 살펴보기

pivot table이란 기존 테이블 구조를 특정 column을 기준으로 재구조화한 테이블을 말합니다.

특정 column을 기준으로 pivot하기 때문에, 어떤 column에 어떤 연산을 하느냐에 따라서 만들어지는 결과가 바뀝니다.

주로 어떤 column을 기준으로 데이터를 해석하고 싶을 때 사용합니다.

# 성별을 기준으로 생존률 파악 --> Mean vs Sum
pd.pivot_table(data=titanic, index=['Sex'], values=['Survived'], aggfunc='mean')

# 사회 계급을 기준으로 생존률 파악
pd.pivot_table(data=titanic, index=['Sex', 'Pclass'], values=['Survived'], aggfunc=['count', 'sum', 'mean'])

2. Numpy

1) Numpy Array and Operation

numpy의 기본적인 사용법에 대해서 배워봅니다.

numpy에서 numpy.array를 만드는 여러가지 방법과 지원하는 연산자에 대해서 공부합니다.

1. Numpy Array creation

# numpy 라이브러리를 불러옵니다.
import numpy as np
# 파이썬 리스트 선언
data = [1, 2, 3, 4, 5]
data

>>> [1, 2, 3, 4, 5]

# 파이썬 2차원 리스트(행렬) 선언
data2 = [ [1, 2], [3, 4] ]
data2

>>> [[1, 2], [3, 4]]

numpy.array VS python list

np.array는 생성된 이후에 크기 변경이 불가능

np.array는 "무조건" 모든 원소의 dtype이 동일해야 함

numpy는 위의 세팅을 만족하는 것으로 인해서, 사용할 연산자와 연산 횟수가 고정되는 이점이 있다!

# 파이썬 list를 numpy array로 변환합니다.
arr = np.array(data)
# numpy array를 만드는a 방식의 대부분은 파이썬 리스트를 np.array로 변환하는 방식입니다.
arr

>>> array([1, 2, 3, 4, 5])

# 2차원 리스트를 np.array로 만듭니다.
arr2 = np.array(data2) # data2라는 리스트를 numpy array로 만들어라.
arr2

>>> array([[1, 2],
      	   [3, 4]])

2. Array Arithmetic (like vector) --> Universal Function

# v1 = (1, 2, 3), v2 = (4, 5, 6) 벡터 2개 생성하기.
v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])

# 리스트로 더하기 연산해보기 ---> concatenation
[n1 + n2 for n1, n2 in zip([1, 2, 3], [4, 5, 6])]

>>> [5, 7, 9]

#  vector addition
v1 + v2

>>> array([5, 7, 9])

#  vector subtraction
v1 - v2

>>> array([-3, -3, -3])

# (not vector operation) elementwise multiplication
v1 * v2

>>> array([ 4, 10, 18])

# (not vector operation) elementwise division
v1 / v2

>>> array([0.25, 0.4 , 0.5 ])

# dot product : 같은 위치에 있는 원소들을 각자 곱하고, 모두 더한 결과. (내적)
v1 @ v2

>>> 32

2) Numpy Methods

numpy에서 사용되는 여러가지 함수들을 사용해봅시다.

1. Math Functions

# 표준정규분포에서 random sampling을 한 원소를 가지는 5x3 행렬을 만든다.
np.random.seed(42)  ## seed number
mat1 = np.random.randn(5, 3)
mat1

>>> array([[ 0.49671415, -0.1382643 ,  0.64768854],
           [ 1.52302986, -0.23415337, -0.23413696],
           [ 1.57921282,  0.76743473, -0.46947439],
           [ 0.54256004, -0.46341769, -0.46572975],
           [ 0.24196227, -1.91328024, -1.72491783]])

# mat1에 절대값 씌우기
np.abs(mat1)

>>> array([[0.49671415, 0.1382643 , 0.64768854],
           [1.52302986, 0.23415337, 0.23413696],
           [1.57921282, 0.76743473, 0.46947439],
           [0.54256004, 0.46341769, 0.46572975],
           [0.24196227, 1.91328024, 1.72491783]])

# mat1 제곱하기
np.square(mat1)

>>> array([[0.24672495, 0.01911702, 0.41950044],
           [2.31961994, 0.0548278 , 0.05482011],
           [2.49391312, 0.58895606, 0.2204062 ],
           [0.2943714 , 0.21475596, 0.2169042 ],
           [0.05854574, 3.66064129, 2.97534153]])
           
# mat1의 제곱근 구하기
np.sqrt(mat1)           
           
>>> array([[0.70477951,        nan, 0.80479099],
           [1.23411096,        nan,        nan],
           [1.25666734, 0.87603352,        nan],
           [0.73658675,        nan,        nan],
           [0.49189661,        nan,        nan]])           

# linear algebra functions
vec = np.array([1, 0, 1])

# 1. norm
np.linalg.norm(vec) # sqrt2

# 2. eigenvalue
np.linalg.eig([[1, 0], [0, 1]])

>>> (array([1., 1.]),
     array([[1., 0.],
            [0., 1.]]))

2. Aggregation functions

np.random.seed(0xC0FFEE)
mat2 = np.random.rand(3, 2)
mat2

>>> array([[0.57290783, 0.81519505],
           [0.92585076, 0.09358959],
           [0.26716135, 0.96059676]])
           
# Summation
# axis=0 : column
# axis=1 : row
np.sum(mat2, axis=1)           
           
>>> array([1.38810288, 1.01944035, 1.22775812])           
           
# mean
np.mean(mat2)

>>> 0.6058835588121987

# std
np.std(mat2)

>>> 0.3292104202289578

mat2

>>> array([[0.57290783, 0.81519505],
           [0.92585076, 0.09358959],
           [0.26716135, 0.96059676]])
           
# min, max
#np.min(mat2, axis=0)
np.max(mat2, axis=1)           
           
>>> array([0.81519505, 0.92585076, 0.96059676])          
           
# 최소값이 있는 Index
np.argmin(mat2, axis=0)

>>> array([2, 1])
           
# 최대값이 있는 Index
np.argmax(mat2, axis=1)

>>> array([1, 0, 1])

3) Performance Check

Universal Function 기능을 통해 반복문을 사용한 것보다 훨씬 빠른 성능을 냅니다.

직접 실험을 통해 그 차이를 확인해보겠습니다.

np.random.seed(0)

def reverse_num(values):
    output = np.empty(len(values))
    
    for i in range(len(values)):
        output[i] = 1.0 / values[i]
    
    return output
    
# 1부터 100까지 범위에서 1000000개를 랜덤으로 뽑아서 array를 만듭니다.
big_array = np.random.randint(1, 101, 10000000)    
    
%timeit reverse_num(big_array)    
    
>>> 6.71 s ± 28.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit 1.0 / big_array

>>> 10.4 ms ± 214 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

4) 수식 구현 - 가까운 데이터 찾기!

# euclidean distance
def euclidean_distance(x, y):
    # x, y : np.array (n-dim vector)
    return np.sqrt(np.sum(np.square(x - y)))

# cosine distance
def cosine_distance(x, y):
    ## TO-DO ##
    # 주어진 x, y에 대해서 x, y 사이의 cosine distance를 계산해보세요.
    # 이론상의 최소값은 0, 최대값은 2입니다.
    ## cosine distance는 1 - cosine similarity로 정의됩니다.
    n1 = np.sqrt(np.sum(np.square(x)))
    n2 = np.sqrt(np.sum(np.square(y)))
    cosine_sim = (x @ y) / (n1*n2)
    return 1 - cosine_sim
    
v1 = np.array([1, 2, 3, -4])
v2 = np.array([-1, 2, 5, 1])

euclidean_distance(v1, v2), cosine_distance(v1, v2)

>>> (5.744562646538029, 0.5409219149512329)

3. 데이터 시각화 Seaborn

엄청나게 화려한 시각화 기법들을 제공하며, 기본적으로 이쁩니다.

histplot, barplot, jointplot, lineplot, ...

pandas DataFrame과 매우 호환이 잘 됩니다.

e.g. sns.xxxplot(data=df) <--- 기본세팅!

  • 데이터 로드
# 라이브러리와 데이터를 불러오고, 시각화를 위한 세팅을 합니다.
import seaborn as sns

data = sns.load_dataset('penguins')
data = data.dropna()
data
  • Histplot

    가장 기본적으로 사용되는 히스토그램을 출력하는 plot.

    전체 데이터를 특정 구간별 정보를 확인할 때 사용합니다.

# penguin 데이터에 histplot을 출력합니다.
sns.histplot(data=data, x='body_mass_g',
            hue='species', multiple='stack', palette='Set2',
            bins=30)

  • Displot

distribution들을 여러 subplot들로 나눠서 출력해주는 plot.

displot에 kind를 변경하는 것으로, histplot, kdeplot, ecdfplot 모두 출력이 가능합니다.

# penguin 데이터에 displot을 출력합니다.
sns.displot(data=data, x='bill_length_mm',
           kind='hist', col='sex', row='island',
           hue='species')

  • Barplot

어떤 데이터에 대한 값의 크기를 막대로 보여주는 plot. (a.k.a. 막대그래프)

가로 / 세로 두 가지로 모두 출력 가능합니다.

히스토그램과는 다릅니다!

# penguin 데이터에 barplot을 출력합니다.
sns.barplot(data=data, y='species', x='body_mass_g', hue='sex',
           errorbar=None)

  • Countplot

범주형 속성을 가지는 데이터들의 histogram을 보여주는 plot.

종류별 count를 보여주는 방법입니다.

# penguin 데이터에 countplot을 출력합니다.
sns.countplot(data=data, x='island')

  • Boxplot

데이터의 각 종류별로 사분위 수(quantile)를 표시하는 plot.

특정 데이터의 전체적인 분포를 확인하기 좋은 시각화 기법입니다.

box와 전체 range의 그림을 통해 outlier를 찾기 쉽습니다. (IQR : Inter-Quartile Range)

# penguin 데이터에 boxplot을 출력합니다.
sns.boxplot(data=data[['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm']])
# What is boxplot?

  • Violinplot

데이터에 대한 분포 자체를 보여주는 plot.

boxplot과 비슷하지만, 전체 분포에 대한 그림을 보여준다는 점에서 boxplot과 다릅니다.

보통 boxplot과 함께 표시하면, 평균 근처에 데이터가 얼마나 있는지(boxplot) 전체적으로 어떻게 퍼져있는지(violinplot) 모두 확인이 가능합니다.

# penguin 데이터에 violinplot을 출력합니다.
sns.violinplot(data=data, x='species', y='body_mass_g')

  • Lineplot

특정 데이터를 x, y로 표시하여 관계를 확인할 수 있는 plot. (선 그래프)

수치형 지표들 간의 경향을 파악할 때 많이 사용합니다.

# penguin 데이터에 lineplot을 출력합니다.
# sns.lineplot(data=data, x='body_mass_g', y='flipper_length_mm', errorbar=None,
#             hue='species')

sns.lineplot(x=data['body_mass_g'], y=data['flipper_length_mm'], errorbar=None)

  • Pointplot

특정 수치 데이터를 error bar와 함께 출력해주는 plot.

수치 데이터를 다양한 각도에서 한 번에 바라보고 싶을 때 사용합니다.

데이터와 error bar를 한 번에 찍어주기 때문에, 살펴보고 싶은 특정 지표들만 사용하는 것이 좋습니다.

# penguin 데이터에 pointplot을 출력합니다.
sns.pointplot(data=data, x='species', y='flipper_length_mm')

  • Scatterplot

lineplot과 비슷하게 x, y에 대한 전체적인 분포를 확인하는 plot.

lineplot은 경향성에 초점을 둔다면, scatterplot은 데이터 그 자체가 퍼져있는 모양에 중점을 둡니다.

# penguin 데이터에 scatterplot을 출력합니다.
sns.scatterplot(data=data, x='bill_depth_mm', y='bill_length_mm')

  • Pairplot

주어진 데이터의 각 feature들 사이의 관계를 표시하는 Plot.

scatterplot, FacetGrid, kdeplot을 이용하여 feature간의 관계를 잘 보여줍니다.

각 feature에 대해 계산된 모든 결과를 보여주기 때문에, feature가 많은 경우 사용하기 적합하지 않습니다.

# penguin 데이터에 pairplot을 출력합니다.
sns.pairplot(data=data, hue='species', corner=True)

  • Heatmap

정사각형 그림에 데이터에 대한 정도 차이를 색 차이로 보여주는 plot.

말 그대로 heatmap이기 때문에, 열화상카메라로 사물을 찍은 것처럼 정보의 차이를 보여줍니다.

pairplot과 비슷하게 feature간 관계를 시각화할 때 많이 사용합니다.

상관관계란?

어떤 X값의 변화에 따라 Y값의 선형적으로 변화하는지를 측정한 지표.

[-1, 1]

e.g. 아이스크림 판매량 증가 <----> 상어에 물린 사람 수

# 각 feature간 상관관계를 파악하기 위해 Correlation matrix를 만듭니다.
data.corr()

# penguin 데이터에 heatmap을 출력합니다.
sns.heatmap(data.corr(), annot=True, fmt='.4f', cmap='viridis')

4. Instacart EDA

Instacart data로 구매 패턴 분석해보기

아무것도 모르는 데이터를 가져와서 EDA를 하려면 어떤 것들을 확인해야할까?

EDA의 process는 어떻게 될까?

EDA를 잘하려면 어떤 것들이 필요할까?

[데이터 링크] https://www.kaggle.com/c/instacart-market-basket-analysis/data

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 데이터를 불러오면 처음 무조건 파악해야하는 것!
aisles = pd.read_csv('./data/aisles.csv')
departments = pd.read_csv('./data/departments.csv')
orders = pd.read_csv('./data/orders.csv')
order_products_train = pd.read_csv('./data/order_products__train.csv')
products = pd.read_csv('./data/products.csv')

1. 크기, 메모리

orders.info(memory_usage='deep') # 340만개, 350MB
#order_products_train.info() # 140만개
#products.info()

>>> <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 3421083 entries, 0 to 3421082
    Data columns (total 7 columns):
     #   Column                  Dtype  
    ---  ------                  -----  
     0   order_id                int64  
     1   user_id                 int64  
     2   eval_set                object 
     3   order_number            int64  
     4   order_dow               int64  
     5   order_hour_of_day       int64  
     6   days_since_prior_order  float64
    dtypes: float64(1), int64(5), object(1)
    memory usage: 358.8 MB

2. row, column의 의미

#aisles # 중분류
#departments # 대분류
#products # 실제 품목
#orders
order_products_train

# Q1. 어떤 Product가 가장 많이 reorder가 되었는가?
# Q1-1. product 개수는 49688개인데, Q1의 결과로 왜 39123개만 나올까요?
data = pd.merge(order_products_train, products, on='product_id', how='inner')

pd.pivot_table(data=data, index=['product_name'], values='reordered', aggfunc='sum')

# Q2. 가장 많이 주문된 Product는?
pd.pivot_table(data=data, index=['product_name'], values='reordered', aggfunc='sum')\
                    .sort_values(by='reordered', ascending=False)

# Q3. reorder가 가장 많이 일어나는 department는?
data = pd.merge(data, departments, on='department_id', how='inner')
data.pivot_table(index='department', values='reordered', aggfunc='sum').sort_values(by='reordered', ascending=False)

data = pd.merge(data, aisles, on='aisle_id')
data

orders = orders[orders.eval_set == 'train']
orders

# Q4. order를 가장 많이 한 user는?
orders.pivot_table(index='user_id', values='order_number', aggfunc='count').sort_values(by='order_number',
                                                                                       ascending=False)
pt = orders.pivot_table(index='user_id', values='order_number', aggfunc='max')
pt.sort_values(by='order_number', ascending=False) # 100
pt[pt.order_number == 100] # order_number는 최소 4에서 최대 100.

# Q5. order가 가장 많이 일어난 요일은?
orders.order_dow.value_counts()
sns.countplot(data=orders, x='order_dow')

# Q6. 재구매율이 높은 product top10은?
data.pivot_table(index='product_name', values='reordered', aggfunc='mean')\
                    .sort_values(by='reordered', ascending=False)

# Q7. 재구매가 많이 일어나는 요일?
data = pd.merge(data, orders, on='order_id')
data.pivot_table(index='order_dow', values='reordered', aggfunc='sum').sort_values(by='reordered', ascending=False)

# Q8. 사람들이 평균적으로 재구매를 하는 기간은?
data.days_since_prior_order.mean()

>>> 17.0661258672976
# Q9. days_since_prior에 따른 reorder 횟수 변화를 그래프로 그려봅시다.
data.days_since_prior_order.value_counts()
pt = data.pivot_table(index='days_since_prior_order', values='reordered', aggfunc='sum')
pt = pt.reset_index()[:-1]

plt.figure(figsize=(20, 6))
#sns.barplot(x=pt.index.astype(int), y=pt.reordered)
#sns.lineplot(x=pt.index.astype(int), y=pt.reordered, lw=4)
sns.barplot(x=pt.days_since_prior_order.astype(int), y=pt.reordered)
sns.lineplot(x=pt.days_since_prior_order.astype(int), y=pt.reordered, lw=4)

# Q10. user들이 구매 패턴에 따라 어떤 그룹으로 묶일까?
## Customer Segmentation
# Q10-1. user를 어떻게 정의할것인가? (= user profiling) --> 어떤 department에 product를 몇개씩 샀는가 & reordered 비율
pd.pivot_table(data=data[data.user_id == 112108], index='department', values='order_dow', aggfunc='count')

pd.pivot_table(data=data[data.user_id == 72775], index='department', values='order_dow', aggfunc='count')

user_matrix = pd.crosstab(data.user_id, data.department)
user_matrix

# Q10-2. 비슷한 유저를 어떻게 판단할것인가? ---> clustering
from sklearn.cluster import KMeans

model = KMeans(n_clusters=4, random_state=42)
labels = model.fit_predict(user_matrix)
df = pd.DataFrame({'user_id' : user_matrix.index, 'group_id' : labels})
data = pd.merge(data, df, on='user_id')
data

g0 = data[data.group_id == 0]
g0.department.value_counts()[:10]

>>> produce         74240
    dairy eggs      62297
    beverages       54829
    snacks          43126
    frozen          36200
    pantry          29538
    household       19899
    bakery          17258
    deli            14858
    canned goods    14142
    Name: department, dtype: int64
g1 = data[data.group_id == 1]
g1.department.value_counts()[:10]

>>> produce            122132
    dairy eggs          36285
    snacks              15352
    frozen              13413
    pantry              12897
    beverages           11661
    canned goods         8983
    deli                 7423
    bakery               7201
    dry goods pasta      6835
    Name: department, dtype: int64
g2 = data[data.group_id == 2]
g2.department.value_counts()[:10]

>>> produce            162677
    dairy eggs          45133
    pantry              18989
    beverages           18820
    frozen              18806
    snacks              18451
    canned goods        12889
    deli                10672
    bakery              10666
    dry goods pasta      9418
    Name: department, dtype: int64
g3 = data[data.group_id == 3]
g3.department.value_counts()[:10]

>>> dairy eggs         73336
    produce            50038
    snacks             41933
    frozen             32007
    beverages          28736
    pantry             19818
    bakery             13269
    deli               11338
    canned goods       10785
    dry goods pasta    10522
    Name: department, dtype: int64

0개의 댓글

관련 채용 정보