tensorflow로 시작해서 그런지 keras쪽이 더 눈에 익기는 한데, PyTorch도 쓰다보면 익숙해지겠지.
전 회사 다닐때 비해서 많은 발전이 있기는 했지만, 아직도 많이 부족하다는 것을 느낀다. 언제쯤이면 어느 정도 괜찮다 싶다는 생각이 들려나. 
 
 
 
1. Embedding을 사용하며, 단어 집합(vocabulary)의 크기가 5,000이고 임베딩 벡터의 차원 100
 
2. 은닉층에서는 SimpleRNN을 사용하며, 은닉 상태의 크기는 128입니다.
 
3. 훈련에 사용하는 모든 샘플의 길이는 30으로 가정합니다.
 
4. 이진 분류를 수행하는 모델로, 출력층의 뉴런은 1개로 시그모이드 함수를 사용합니다.
 
5. 은닉층은 1개입니다.
 
위의 정보를 이용해서 tensorflow.keras를 이용해서 모델 생성하는 파이썬 코드를 만들어주고 총 파라미터 개수를 알려주세요.

 

아래는 주어진 조건에 따라 모델을 구현한 Python 코드와 총 파라미터 개수를 계산한 결과입니다:

모델 구현

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, SimpleRNN, Dense

# 모델 파라미터
vocab_size = 5000          # 단어 집합 크기
embedding_dim = 100        # 임베딩 벡터 차원
sequence_length = 30       # 샘플 길이
hidden_units = 128         # SimpleRNN 은닉 상태 크기

# 모델 생성
model = Sequential([
    Embedding(input_dim=vocab_size, output_dim=embedding_dim, input_length=sequence_length),
    SimpleRNN(units=hidden_units, activation='tanh'),
    Dense(1, activation='sigmoid')
])

# 모델 요약 출력
model.summary()

 

총 파라미터 계산

  1. Embedding Layer:
    • vocab_size×embedding_dim=5000×100=500,000\text{vocab\_size} \times \text{embedding\_dim} = 5000 \times 100 = 500,000
  2. SimpleRNN Layer:
    • SimpleRNN의 파라미터 계산 공식: RNN 파라미터 수=(input_dim+units+1)×units\text{RNN 파라미터 수} = (\text{input\_dim} + \text{units} + 1) \times \text{units} 여기서,
      • input_dim=embedding_dim=100\text{input\_dim} = \text{embedding\_dim} = 100
      • units=128\text{units} = 128
      • 11은 bias 항목
      (input_dim+units+1)×units=(100+128+1)×128=229×128=29,312(\text{input\_dim} + \text{units} + 1) \times \text{units} = (100 + 128 + 1) \times 128 = 229 \times 128 = 29,312
  3. Dense Layer:
    • units_in×units_out+bias=128×1+1=129\text{units\_in} \times \text{units\_out} + \text{bias} = 128 \times 1 + 1 = 129

총 파라미터

  • Embedding Layer: 500,000
  • SimpleRNN Layer: 29,312
  • Dense Layer: 129
  • 총 파라미터: 500,000+29,312+129=529,441500,000 + 29,312 + 129 = 529,441

출력

model.summary()를 실행하면 다음과 유사한 출력이 나타납니다:

 

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 embedding (Embedding)       (None, 30, 100)          500000    
                                                                 
 simple_rnn (SimpleRNN)      (None, 128)              29312     
                                                                 
 dense (Dense)               (None, 1)                129       
                                                                 
=================================================================
Total params: 529,441
Trainable params: 529,441
Non-trainable params: 0
_________________________________________________________________

 

아래는 주어진 조건을 만족하는 PyTorch 기반 모델 구현 코드입니다.

 

import torch
import torch.nn as nn

class SimpleRNNBinaryClassifier(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_units):
        super(SimpleRNNBinaryClassifier, self).__init__()
        self.embedding = nn.Embedding(num_embeddings=vocab_size, embedding_dim=embedding_dim)
        self.rnn = nn.RNN(input_size=embedding_dim, hidden_size=hidden_units, batch_first=True)
        self.fc = nn.Linear(in_features=hidden_units, out_features=1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        # Embedding layer
        x = self.embedding(x)  # Shape: (batch_size, sequence_length, embedding_dim)
        # RNN layer
        output, hidden = self.rnn(x)  # hidden has shape (1, batch_size, hidden_units)
        # Fully connected layer
        x = self.fc(hidden.squeeze(0))  # Shape: (batch_size, 1)
        # Sigmoid activation
        x = self.sigmoid(x)
        return x

# 모델 파라미터
vocab_size = 5000
embedding_dim = 100
sequence_length = 30
hidden_units = 128

# 모델 생성
model = SimpleRNNBinaryClassifier(vocab_size, embedding_dim, hidden_units)

# 모델 요약 출력 (파라미터 개수 포함)
print(model)

# 총 파라미터 개수 계산
total_params = sum(p.numel() for p in model.parameters())
print(f"Total parameters: {total_params}")

 

주요 변경점

  1. Embedding Layer:
    • nn.Embedding을 사용하여 단어 집합 크기와 임베딩 벡터 차원 설정.
  2. SimpleRNN Layer:
    • nn.RNN을 사용하여 은닉 상태 크기와 입력 크기 정의.
    • batch_first=True를 설정해 입력 텐서를 (batch_size, sequence_length, embedding_dim) 형태로 맞춤.
  3. Dense Layer:
    • nn.Linear을 사용해 은닉 상태의 마지막 출력에서 1차원 출력 생성.
  4. Sigmoid Activation:
    • 이진 분류 문제를 위해 nn.Sigmoid를 적용.

출력 예시

위 코드를 실행하면 모델 구조와 총 파라미터 개수를 확인할 수 있습니다.

예:

 

SimpleRNNBinaryClassifier(
  (embedding): Embedding(5000, 100)
  (rnn): RNN(100, 128, batch_first=True)
  (fc): Linear(in_features=128, out_features=1, bias=True)
  (sigmoid): Sigmoid()
)
Total parameters: 529441

반응형

'Python, PySpark' 카테고리의 다른 글

torch.nn.Embedding()  (0) 2025.01.04
NewsClassifier  (0) 2025.01.04
Python Scheduler  (0) 2024.12.10
networkx - sql과 함께  (0) 2024.10.24
Python networkx  (1) 2024.10.10

 구릅 코랩과 챗지피티가 아니었다면, 머신러닝을 지나 딥러닝/NLP까지 도착하지는 못했을 것이다. 늘 고맙게 감사하게 생각한다.

 

torch.nn.Embedding에서 _weight 옵션은 임베딩 행렬의 초기값을 설정하는 데 사용됩니다. 이 매개변수는 주로 Embedding.from_pretrained() 메서드 내부에서 사용되며, 사용자가 직접 임베딩 행렬을 지정할 수 있습니다.


기본 동작

nn.Embedding을 생성할 때 _weight를 명시적으로 설정하면, 해당 값을 임베딩 행렬로 사용합니다. 이를 통해 사전 학습된 임베딩(예: GloVe, FastText)을 모델 초기화에 활용할 수 있습니다.


_weight 매개변수

  • 타입: torch.Tensor
  • 크기: (num_embeddings, embedding_dim)
    • num_embeddings: 사전에 포함된 고유 토큰 수.
    • embedding_dim: 각 토큰의 임베딩 벡터 차원.
  • 역할: 초기 임베딩 행렬로 사용되며, 학습 가능 여부는 모델 설정에 따라 달라집니다.
  • 주의: _weight는 Embedding 객체를 초기화할 때만 사용할 수 있으며, 이후에는 접근하거나 수정할 수 없습니다.

사용 예제

1. _weight를 수동으로 설정

import torch
import torch.nn as nn

# 사용자 지정 임베딩 행렬 (사전 학습된 값 예시)
pretrained_weights = torch.tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]])

# nn.Embedding 초기화 시 _weight 설정
embedding = nn.Embedding(num_embeddings=3, embedding_dim=2, _weight=pretrained_weights)

# 입력 데이터
input_indices = torch.tensor([0, 2])
output = embedding(input_indices)

print(output)
# 출력: [[0.1, 0.2], [0.5, 0.6]]

2. from_pretrained()와 비교

Embedding.from_pretrained()는 _weight를 설정하는 더 편리한 방법입니다.

# 동일한 pretrained_weights 사용
embedding = nn.Embedding.from_pretrained(pretrained_weights)

# 입력 데이터
input_indices = torch.tensor([0, 2])
output = embedding(input_indices)

print(output)
# 출력: [[0.1, 0.2], [0.5, 0.6]]

사전 학습된 임베딩 사용

_weight를 활용하면 사전 학습된 임베딩을 쉽게 사용할 수 있습니다. 예를 들어, GloVe나 FastText 임베딩을 가져와 torch.Tensor로 변환한 뒤 _weight에 전달하면 됩니다.

import numpy as np

# 사전 학습된 GloVe 임베딩 (numpy 배열)
pretrained_glove = np.array([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]])

# torch.Tensor로 변환
pretrained_weights = torch.tensor(pretrained_glove)

# _weight로 초기화
embedding = nn.Embedding(num_embeddings=3, embedding_dim=2, _weight=pretrained_weights)

# 입력 데이터
input_indices = torch.tensor([1])
output = embedding(input_indices)

print(output)
# 출력: [[0.3, 0.4]]

_weight의 학습 가능 여부

  • _weight로 설정된 임베딩 행렬은 기본적으로 학습 가능합니다.
  • 학습을 방지하려면 from_pretrained()의 freeze=True를 사용하거나, 수동으로 파라미터를 고정해야 합니다:
    embedding = nn.Embedding.from_pretrained(pretrained_weights, freeze=True)
    

요약

  • _weight는 초기 임베딩 행렬을 지정하는 데 사용됩니다.
  • 주로 사전 학습된 임베딩을 사용할 때 활용됩니다.
  • 학습 가능 여부를 설정하려면 추가적인 설정이 필요합니다.

더 자세한 사항이나 추가적인 질문이 있다면 알려주세요! 😊

반응형

'Python, PySpark' 카테고리의 다른 글

RNN in python with Keras, PyTorch  (0) 2025.01.20
NewsClassifier  (0) 2025.01.04
Python Scheduler  (0) 2024.12.10
networkx - sql과 함께  (0) 2024.10.24
Python networkx  (1) 2024.10.10
class NewsClassifier(nn.Module):
def __init__(self, embedding_size, num_embeddings, num_channels,
hidden_dim, num_classes, dropout_p,
pretrained_embeddings = None, padding_idx = 0):
"""
매개변수:
embedding_size (int): 임베딩 벡터의 크기
num_embeddings (int): 임베딩 벡터의 개수
num_channels (int): 합성곱 커널 개수
hidden_dim (int): 은닉 차원 크기
num_classes (int): 클래스 개수
dropout_p (float): 드롭아웃 확률
pretrained_embeddings (numpy.array): 사전 훈련된 단어 임베딩
기본값은 None
padding_idx (int): 패딩 인덱스
"""
super(NewsClassifier, self).__init__()

if pretrained_embeddings is None:
self.emb = nn.Embedding(embedding_dim = embedding_size,
num_embeddings = num_embeddings,
padding_idx = padding_idx )
else:
pretrained_embeddings = torch.from_numpy(pretrained_embeddings).float()
self.emb = nn.Embedding(embedding_dim = embedding_size,
num_embeddings = num_embeddings,
padding_idx = padding_idx,
_weight = pretrained_embeddings)

self.convnet = nn.Sequential(
nn.Conv1d(in_channels = embedding_size,
out_channels = num_channels, kernel_size = 3),
nn.ELU(),
nn.Conv1d(in_channels = num_channels, out_channels = num_channels,
kernel_size = 3, stride = 2),
nn.ELU(),
nn.Conv1d(in_channels = num_channels, out_channels = num_channels,
kernel_size = 3, stride = 2),
nn.ELU(),
nn.Conv1d(in_channels = num_channels, out_channels = num_channels,
kernel_size = 3),
nn.ELU()
)

self._dropout_p = dropout_p
self.fc1 = nn.Linear(num_channels, hidden_dim)
self.fc2 = nn.Linear(hidden_dim, num_classes)

def forward(self, x_in, apply_softmax = False):
""" 분류기의 정방향 계산

매개변수:
x_in (torch.Tensor): 입력 데이터 텐서
x_in.shape는 (batch, dataset._max_seq_length)입니다.
apply_softmax (bool): 소프트맥스 활성화 함수를 위한 플래그
크로스-엔트로피 손실을 사용하려면 False로 지정합니다.
반환값:
결과 텐서. tensor.shape은 (batch, num_classes)입니다.
"""

# 임베딩을 적용하고 특성과 채널 차원을 바꿉니다.
x_embedded = self.emb(x_in).permute(0, 2, 1)

features = self.convnet(x_embedded)

# 평균 값을 계산하여 부차적인 차원을 제거합니다.
remaining_size = features.size(dim = 2)
#print(f"remaining_size: {remaining_size}")
features = F.avg_pool1d(features, remaining_size).squeeze(dim = 2)
features = F.dropout(features, p = self._dropout_p)

# MLP 분류기
intermediate_vector = F.relu(F.dropout(self.fc1(features), p = self._dropout_p))
prediction_vector = self.fc2(intermediate_vector)

if apply_softmax:
prediction_vector = F.softmax(prediction_vector, dim = 1)

return prediction_vector

주어진 `NewsClassifier` 모델은 PyTorch를 기반으로 한 뉴스 분류를 위한 신경망입니다. 주요 구조와 작동 방식을 아래에 정리했습니다.

---

### **주요 특징**

1. **임베딩 레이어**:
   - `pretrained_embeddings`(사전 학습된 임베딩)이 제공되면 이를 사용하여 임베딩 레이어를 초기화합니다. 
   - 제공되지 않으면 새로 임베딩 레이어를 생성합니다.
   - `padding_idx`는 패딩 토큰이 학습에 영향을 주지 않도록 설정합니다.

2. **합성곱 신경망(CNN)**:
   - 여러 개의 `Conv1d` 레이어로 구성된 합성곱 구조를 통해 입력 데이터를 처리합니다.
   - 각 합성곱 레이어 뒤에 `ELU` 활성화 함수가 적용됩니다.
   - `stride`와 `kernel_size` 설정으로 시퀀스 길이를 점진적으로 줄입니다.

3. **글로벌 평균 풀링**:
   - `avg_pool1d`를 사용하여 시퀀스 차원을 고정된 크기로 줄입니다.
   - 이를 통해 합성곱 레이어에서 추출된 특징을 요약합니다.

4. **완전 연결 레이어 (MLP)**:
   - 두 개의 선형 레이어(`fc1`, `fc2`)가 최종 분류기를 형성합니다.
   - 드롭아웃 레이어를 사용하여 과적합을 방지합니다.

5. **소프트맥스 활성화 함수 (선택적)**:
   - `apply_softmax` 플래그를 통해 소프트맥스를 출력에 적용할지 선택할 수 있습니다.
   - 이는 확률 분포를 해석하거나 추론 시 유용합니다.

---

### **정방향 계산 과정**

1. **임베딩**:
   - 입력 토큰을 임베딩 레이어를 통해 밀집 벡터(dense vector)로 변환합니다.
   - Conv1d 레이어에 적합하도록 시퀀스 축과 채널 축을 교환합니다.

2. **합성곱 및 풀링**:
   - 합성곱 레이어를 통해 특징을 추출하고 시퀀스 길이를 줄입니다.
   - `avg_pool1d`로 시퀀스 차원을 완전히 제거해 고정 크기 벡터를 만듭니다.

3. **분류**:
   - 완전 연결 네트워크를 통해 분류 작업을 수행합니다.
   - 드롭아웃을 적용하여 과적합을 방지합니다.
   - 최종 출력은 `(배치 크기, 클래스 개수)`의 텐서입니다.

4. **소프트맥스**:
   - `apply_softmax=True`일 경우, 출력 텐서를 확률 분포로 변환합니다.

---

### **개선 가능성**

1. **합성곱에서 패딩 사용**:
   - `padding="same"`을 적용하여 시퀀스 양 끝의 정보 손실을 방지할 수 있습니다.

2. **배치 정규화 (Batch Normalization)**:
   - 합성곱 레이어 뒤에 배치 정규화를 추가하면 학습 안정성과 수렴 속도가 개선됩니다.

3. **파라미터 초기화**:
   - Xavier 또는 Kaiming 초기화를 사용하면 모델 성능이 더 좋아질 수 있습니다.

4. **문서화**:
   - 중간 텐서들의 예상 크기를 주석으로 추가하면 가독성이 높아집니다.

5. **에러 핸들링**:
   - 입력 텐서의 차원을 검증하여 데이터 형태가 맞지 않을 경우 바로 에러를 출력하도록 설정합니다.

---

### **도움이 필요한 점이 있나요?**
위 모델을 개선하거나 학습에 사용할 코드를 추가적으로 작성해드릴까요? 😊

반응형

'Python, PySpark' 카테고리의 다른 글

RNN in python with Keras, PyTorch  (0) 2025.01.20
torch.nn.Embedding()  (0) 2025.01.04
Python Scheduler  (0) 2024.12.10
networkx - sql과 함께  (0) 2024.10.24
Python networkx  (1) 2024.10.10

PyTorch의 **optim.lr_scheduler.ReduceLROnPlateau**는 학습 중에 **손실 함수가 개선되지 않을 때 학습률(learning rate)**을 줄이는 데 사용되는 스케줄러입니다. 학습률이 낮아지면 모델이 손실 함수의 국소 최적점 근처에서 더 안정적으로 수렴할 수 있습니다.


주요 특징

  • 손실 기반: 다른 스케줄러들이 에폭이나 스텝에 따라 학습률을 조정하는 것과 달리, ReduceLROnPlateau는 특정 **지표(metric)**의 변화 여부에 따라 학습률을 줄입니다.
  • 유연성: 손실이 아니라 정확도, F1 점수 등 다른 지표를 기준으로 설정할 수도 있습니다.
  • 적응적: 훈련 상태에 따라 학습률을 동적으로 조정합니다.

사용 방법

1. 스케줄러 생성

ReduceLROnPlateau는 torch.optim의 옵티마이저와 함께 사용됩니다.

python
코드 복사
from torch.optim.lr_scheduler import ReduceLROnPlateau scheduler = ReduceLROnPlateau( optimizer, mode='min', # 'min': 손실 감소를 목표로 함, 'max': 정확도 등 증가를 목표로 함 factor=0.1, # 학습률을 줄이는 비율 (e.g., 10%로 감소) patience=10, # 지정한 에폭 동안 개선되지 않으면 학습률 감소 verbose=True, # 학습률 조정 시 로그 출력 threshold=1e-4, # 개선 여부를 판단하는 임계값 cooldown=0, # 학습률 감소 후 대기 기간 (초기 감소 방지) min_lr=0, # 학습률의 최저값 )

2. 학습 루프에서 호출

훈련 중 손실 값이나 평가 지표를 기반으로 scheduler.step(metrics)을 호출하여 스케줄러를 업데이트합니다.

python
코드 복사
for epoch in range(num_epochs): train_loss = train_model(model, train_loader, optimizer) val_loss = validate_model(model, val_loader) # 손실 기반으로 스케줄러 업데이트 scheduler.step(val_loss) print(f"Epoch {epoch+1}, Learning Rate: {optimizer.param_groups[0]['lr']}")

주요 매개변수 설명

  1. mode:
    • 'min': 지표의 감소를 목표로 합니다 (e.g., 손실 값).
    • 'max': 지표의 증가를 목표로 합니다 (e.g., 정확도).
  2. factor:
    • 학습률을 감소시키는 비율입니다. 기본값은 0.1로, 학습률이 감소 시 기존의 10%로 설정됩니다.
    • 예: 초기 학습률이 0.01이고 factor=0.1이라면 감소 후 학습률은 0.001이 됩니다.
  3. patience:
    • 지표가 개선되지 않을 때 기다리는 에폭 수입니다.
    • 예: patience=10이면, 지표가 10 에폭 동안 개선되지 않으면 학습률을 감소시킵니다.
  4. verbose:
    • True로 설정하면 학습률이 줄어들 때 메시지를 출력합니다.
  5. threshold:
    • 지표가 개선되었다고 간주할 최소 변화량입니다. 기본값은 1e-4.
  6. cooldown:
    • 학습률이 감소한 후 다시 감소하기 전에 대기하는 에폭 수입니다.
  7. min_lr:
    • 학습률의 최소값을 설정합니다. 이 값 이하로는 학습률이 줄어들지 않습니다.

예제

옵티마이저와 함께 사용

python
코드 복사
import torch import torch.nn as nn import torch.optim as optim model = nn.Linear(10, 1) optimizer = optim.SGD(model.parameters(), lr=0.01) # ReduceLROnPlateau 스케줄러 정의 scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=5, verbose=True) # 학습 루프 for epoch in range(20): val_loss = 0.02 * (20 - epoch) if epoch < 10 else 0.02 # 손실 값 시뮬레이션 # 스케줄러에 손실 값 전달 scheduler.step(val_loss) print(f"Epoch {epoch+1}, LR: {optimizer.param_groups[0]['lr']}")

출력 예제:

vbnet
코드 복사
Epoch 6: reducing learning rate of group 0 to 5.0000e-03. Epoch 12: reducing learning rate of group 0 to 2.5000e-03.

장점

  1. 학습률을 동적으로 조정해 과적합을 방지하고 최적화를 개선할 수 있습니다.
  2. 학습이 정체되는 구간에서 모델이 더 세밀하게 최적화를 수행하도록 도와줍니다.
  3. 손실 외에도 다양한 지표에 적용 가능.

주의사항

  • 지표 설정: scheduler.step(metrics)에서 전달하는 metrics는 스케줄러가 학습률 감소 여부를 판단하는 기준입니다.
  • 초기 학습률 확인: 초기 학습률이 너무 낮으면 학습이 비효율적일 수 있습니다.
  • 조합 사용: 다른 스케줄러(StepLR, CosineAnnealingLR)와 함께 사용할 수도 있지만, 충돌 가능성을 염두에 두고 설정해야 합니다.

이처럼 ReduceLROnPlateau는 학습 과정에서 유용한 도구로, 학습률을 효율적으로 조정하여 모델 성능을 높이는 데 기여할 수 있습니다!

반응형

'Python, PySpark' 카테고리의 다른 글

torch.nn.Embedding()  (0) 2025.01.04
NewsClassifier  (0) 2025.01.04
networkx - sql과 함께  (0) 2024.10.24
Python networkx  (1) 2024.10.10
how to visualize the customer page visit pattern on app?  (0) 2024.09.21

큰 데이터셋의 경우, SQL에서 페이지 이동 정보를 사전에 요약하여 Python으로 가져오는 방식이 훨씬 효율적일 수 있습니다. 이 방법은 각 `page_id`에서 `next_page_id`로의 전환이 얼마나 자주 발생했는지를 미리 계산한 후, Python에서 그래프 형태로 시각화할 수 있습니다.

SQL 단계에서 요약된 데이터를 만드는 방법은 `GROUP BY`와 `COUNT()`를 활용하여 각 페이지 간 전환 빈도를 집계하는 것입니다.

### 1. SQL로 페이지 이동 요약하기

다음 SQL 쿼리는 `page_id`에서 `next_page_id`로의 전환 빈도를 사전에 계산합니다.

```sql
-- Teradata에서 page_id와 next_page_id의 전환을 요약한 SQL 쿼리
SELECT 
    page_id,
    next_page_id,
    COUNT(*) AS transition_count
FROM (
    SELECT 
        session_id,
        page_id,
        LEAD(page_id) OVER (PARTITION BY session_id ORDER BY event_time) AS next_page_id
    FROM 
        your_table
) t
WHERE next_page_id IS NOT NULL
GROUP BY page_id, next_page_id;
```

#### 쿼리 설명:
- **`LEAD()`**: `page_id`의 다음 페이지를 가져옵니다.
- **`GROUP BY`**: `page_id`와 `next_page_id`별로 그룹화하여 전환 빈도를 계산합니다.
- **`COUNT(*)`**: 각 전환(`page_id` -> `next_page_id`)이 발생한 횟수를 집계합니다.

이렇게 사전에 전환 빈도를 요약하면, 큰 데이터셋도 효율적으로 처리할 수 있습니다.

### 2. Python에서 요약된 데이터로 그래프 그리기

이제, 요약된 데이터를 Python으로 가져와서 페이지 이동을 시각화합니다.

```python
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from sqlalchemy import create_engine

# Teradata 연결 설정 (SQLAlchemy 사용)
engine = create_engine('teradata://username:password@host:port/dbname')

# SQL 쿼리로 요약된 데이터 불러오기
query = """
SELECT 
    page_id,
    next_page_id,
    COUNT(*) AS transition_count
FROM (
    SELECT 
        session_id,
        page_id,
        LEAD(page_id) OVER (PARTITION BY session_id ORDER BY event_time) AS next_page_id
    FROM 
        your_table
) t
WHERE next_page_id IS NOT NULL
GROUP BY page_id, next_page_id;
"""

# Teradata에서 데이터를 읽어와 DataFrame으로 저장
df = pd.read_sql(query, engine)

# 엣지 리스트 만들기 (page_id -> next_page_id)와 가중치 추가
edges = df[['page_id', 'next_page_id', 'transition_count']].values.tolist()

# NetworkX 그래프 객체 생성
G = nx.DiGraph()

# 엣지와 가중치를 그래프에 추가
for edge in edges:
    G.add_edge(edge[0], edge[1], weight=edge[2])

# 그래프 시각화 설정
plt.figure(figsize=(8, 6))
pos = nx.spring_layout(G)

# 노드 및 엣지 시각화
nx.draw(G, pos, with_labels=True, node_color='skyblue', node_size=3000, font_size=12, font_weight='bold', edge_color='gray', arrows=True)

# 엣지 가중치(전환 빈도) 표시
edge_labels = nx.get_edge_attributes(G, 'weight')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)

# 그래프 보여주기
plt.title('Page Transitions with Frequency')
plt.show()
```

### 코드 설명:
1. **Teradata에서 요약된 데이터 가져오기**: SQL 쿼리에서 페이지 전환 빈도(`transition_count`)를 포함한 데이터를 Python으로 가져옵니다.
2. **엣지 리스트 생성**: `page_id`, `next_page_id`, 그리고 전환 빈도(`transition_count`)를 포함한 리스트를 생성합니다.
3. **그래프에 가중치 추가**: 각 엣지에 페이지 간 전환 빈도를 가중치로 추가합니다.
4. **NetworkX 그래프 시각화**: 페이지 간 이동을 그래프로 나타내고, 각 엣지에 전환 빈도를 라벨로 표시합니다.

### 요약:
- **SQL에서 요약**: Teradata SQL에서 페이지 이동 전환을 미리 집계하여 전환 빈도를 계산합니다.
- **Python에서 시각화**: 요약된 데이터를 `NetworkX`로 시각화하며, 각 전환 빈도를 엣지 가중치로 표시합니다.

이 방법은 데이터가 매우 클 때도 효율적으로 처리할 수 있으며, SQL에서 최대한 전처리를 진행하여 Python에서 시각화에 집중할 수 있습니다.

반응형

'Python, PySpark' 카테고리의 다른 글

NewsClassifier  (0) 2025.01.04
Python Scheduler  (0) 2024.12.10
Python networkx  (1) 2024.10.10
how to visualize the customer page visit pattern on app?  (0) 2024.09.21
PCA와 PLS 차이점(챗지피티 설명)  (0) 2024.09.21

고객의 `page_id` 이동 정보를 분석하고, 세션 내에서 페이지 간의 연결을 시각화하는 작업을 Python의 `networkx`를 사용해 구현할 수 있습니다. 아래는 이를 위한 예제 코드입니다.

### 예제 코드

```python
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt

# 샘플 데이터프레임 생성
data = {
    'session_id': [1, 1, 1, 2, 2, 3, 3, 3],
    'customer_id': [101, 101, 101, 102, 102, 103, 103, 103],
    'page_id': ['home', 'product', 'cart', 'home', 'checkout', 'home', 'product', 'cart']
}

df = pd.DataFrame(data)

# 페이지 이동 정보를 담은 그래프 생성 함수
def build_page_transition_graph(df):
    # 세션별로 그룹화하여 페이지 이동 순서를 파악
    G = nx.DiGraph()  # 방향 그래프를 사용하여 페이지 이동을 나타냄
    
    for session, group in df.groupby('session_id'):
        pages = group['page_id'].tolist()
        # 각 세션 내 페이지 이동을 간선으로 추가
        for i in range(len(pages) - 1):
            G.add_edge(pages[i], pages[i+1])
    
    return G

# 그래프 생성
G = build_page_transition_graph(df)

# 페이지 이동의 연결 강도 계산 (간선의 가중치 추가)
for (u, v) in G.edges():
    if G.has_edge(u, v):
        if 'weight' in G[u][v]:
            G[u][v]['weight'] += 1
        else:
            G[u][v]['weight'] = 1

# 그래프 시각화 함수
def plot_graph(G):
    pos = nx.spring_layout(G)  # 그래프의 레이아웃 설정
    weights = [G[u][v]['weight'] for u, v in G.edges()]  # 간선의 가중치
    
    plt.figure(figsize=(10, 7))
    nx.draw_networkx_nodes(G, pos, node_color='skyblue', node_size=2000)
    nx.draw_networkx_edges(G, pos, width=weights, edge_color='gray', arrows=True)
    nx.draw_networkx_labels(G, pos, font_size=12, font_color='black')

    plt.title('Page Transition Graph')
    plt.show()

# 그래프 시각화
plot_graph(G)

# 연결이 많이 된 page_id 추출
most_connected_pages = sorted(G.degree, key=lambda x: x[1], reverse=True)
print("Most connected pages:", most_connected_pages)
```

### 코드 설명
1. **데이터 생성**: `session_id`, `customer_id`, `page_id`로 구성된 데이터프레임을 만듭니다.
2. **`build_page_transition_graph` 함수**: 각 세션 내에서 페이지 이동 정보를 추출하여 방향성 그래프(DiGraph)를 만듭니다.
   - 각 세션의 페이지 이동이 간선으로 추가됩니다.
3. **간선 가중치 계산**: 페이지 이동이 얼마나 자주 발생했는지, 간선의 가중치로 설정합니다.
4. **`plot_graph` 함수**: `networkx`와 `matplotlib`을 사용해 페이지 이동 네트워크를 시각화합니다.
5. **가장 많이 연결된 페이지 추출**: 페이지별 연결 강도를 기준으로 정렬해 가장 많이 연결된 페이지를 출력합니다.

### 결과:
- 이 코드는 각 세션에서 페이지 간의 이동을 시각적으로 보여주며, 페이지 이동 횟수에 따른 간선의 굵기가 조정됩니다.
- 또한, 가장 연결이 많이 된 페이지도 출력됩니다.

반응형

'Python, PySpark' 카테고리의 다른 글

Python Scheduler  (0) 2024.12.10
networkx - sql과 함께  (0) 2024.10.24
how to visualize the customer page visit pattern on app?  (0) 2024.09.21
PCA와 PLS 차이점(챗지피티 설명)  (0) 2024.09.21
파이토치 CNN 분석  (2) 2024.08.28

+ Recent posts