데이터 경제

데이터는 4차 산업혁명을 견인하는 핵심 동인으로 데이터 경제는 데이터, 데이터 기술, 데이터 제품 및 서비스에 기반한 경제로 정의됩니다. 이는 4차 산업혁명과 맞물려 데이터가 모든 산업의 발전과 새로운 가치 창출의 촉매 역할을 하는 현재 산업의 전반적인 흐름을 보여주는 용어라고 할 수 있겠습니다.

이 데이터 경제의 정의는 2011년 데이비드 뉴먼의 가트너 보고서(How to Plan, Participate and Prosper in the Data Economy)에서 데이터 경제의 개념이 처음 등장했습니다. 이 보고서에서 빅데이터, 오픈데이터, 연결데이터 등 데이터로 파생되는 경제를 아우르는 용어로 표현되었습니다.

데이터 경제는 어려운 용어이지만 쉽게 정의한다면 “데이터 경제란 모든 유형의 데이터를 분석한 정보를 자산으로 새로운 가치(혁신적 비지니스 모델, 수익성장 등)를 창출하며 성장하는 신흥 경제를 지칭” 한다고 할 수 있습니다.

이러한 데이터 경제를 통해서 파생되는 산업이 데이터 산업으로 데이터의 생산, 수집, 처리, 분석, 유통, 활용 등을 통해 가치를 창출하는 상품과 서비스를 생산하고 제공하는 산업입니다.

https://www.bbc.com/news/entertainment-arts-41559076

한때는 데이터를 3차 산업혁명의 동력이었던 원유에 비유하여 “Data is the new Oil”이라는 말이 있었습니다. 그러나 데이터가 4차 산업혁명의 중요한 동력인것은 맞지만 데이터를 물리적인 재화인 원유와는 차별되어야 한다는 개념이 최근 등장하고 있고 그 이론이 많은 동의를 얻고 있습니다.

특히 데이터는 원유나 기타 물리적인 재화들과는 달리 “비경쟁, 비고갈, 재생, 무제한, 쉽게 운반, 저렴한 가격, 복제가 쉬움, 생태계 존재 등” 다양한 특징이 있습니다.

데이터 경제의 가치창출은 다음과 같은 “공급-수요”가 있고 그 안에 데이터를 유통하고 수용자를 찾아 연결해주는 “중개”가 존재합니다. 중개의 역활은 데이터의 유통과 활용 가이드를 통해서 공급자와 수요자의 매개 역활을 수행합니다.

데이터 산업 활성화 전략 – 4차산업혁명위원회

이러한 데이터 산업은 2019년부터 데이터 분석, 연결, 권리 등으로 발전하고 있습니다. 특히 EU는 GDPR(General Data Protection Regulation)을 통해서 개인의 데이터권리를 보호하도록 사업자의 의무와 벌칙을 강화하고 있습니다. 우리나라도 데이터3법을 통해서 데이터의 사용성을 넓히되 개인의 권리를 보호하는 법안들이 통과되어 실행되고 있습니다. 추후에 데이터3법에 대한 내용을 정리해보겠습니다.

이러한 예전에 없던 신산업이 등장하면서 우리나라도 관련 분야의 신규인력 확충을 위해서 기업과 정부차원의 노력이 계속되고 있습니다.
국내 데이터산업에 종사하고 있는 인력은 총 31만 8,062명으로 전년 대비 7.9% 증가했습니다. 향후 5년 내에 일반산업을 포함하여 전 산업에서 필요로 하는 데이터 직무 인력은 총 2만 2,607명이고 데이터 개발자, 데이터 분석가 순으로 많이 필요하다고 조사되고 있습니다.

향후 5년 내 전산업의 데이터직무 빅데이터 관련 필요 인력
https://kosis.kr/statHtml/statHtml.do?orgId=127&tblId=DT_127004N_122

그러나 이러한 필요에도 불구하고 국내 데이터 경제 발전을 저해하는 몇가지 장애 요인이 있습니다.

첫째, 데이터 활용에 대한 낮은 인식
• 짧은 데이터 활용의 역사로 인해 데이터 활용을 통한 가치 창출에 대한 이해 및 인식 부족
둘째, 데이터 전문 인력 부족
• 데이터산업을 제외한 타 산업의 업체들에 데이터 전문 인력이 공급되고 있지 않아 잠재적 활용 가능성을 가진 기업들의 데이터 활용 부진
셋째, 개인정보 활용 제약
• 개인정보보호법, 정보통신망법 등의 법제로 인해 개인정보 활용에 제약
• 지난 몇 년간 일어난 개인정보유출사건으로 인해 개인정보 활용에 대한 국민적 신뢰 부재
넷째, 데이터 상품 저작권 미비
• 데이터를 가공․분석한 결과에 대한 저작권이 법적으로 보호되지 않아 적극적으로 데이터 상품 개발을 추진할 유인 부족
다셋째, 활용 가능한 원시데이터 부족
• 민간부문에서 거래되는 데이터는 가공 또는 활용이 불가능한 통계형 데이터
• 데이터 분석․가공을 위한 민간부문의 원시 데이터의 양이 절대적으로 부족
여섯째, 공공데이터의 낮은 품질
• 공공데이터의 양은 절대적으로 많으나 이를 활용하기에는 데이터의 질이 너무 낮음
일곱째, 데이터 표준 부재
• 데이터 표준이 부재함에 따라 이종 데이터 간결합 비용 증가
여덟째, 데이터 수요자․공급자 파악의 어려움
• 데이터 거래에 참여할 의사가 있음에도 필요로 하는 데이터를 가진 공급자 또는 자신이 보유한 데이터를 구매할 수요자를 파악하기 어려움
아홉째, 데이터 가공․중개 업체 부족
• 데이터 가공․중개업체들은 데이터 상품 최종 수요자로부터 데이터 상품을 의뢰받고 이를 생산하기 위한 데이터 공급자들에게 데이터를 구매하여 최종 데이터 상품을 생산
• 하지만 데이터 공급자 및 구매자의 연결고리 역할을 하는 데이터 가공․중개 업체의 수가 절대적으로 부족
출처 : ICT기반 신산업 발전을 위한 데이터 거래 활성화 방안(정보통신정책연구원,2018)

연구는 이러한 장애요인을 데이터법제도 정비, 거래소 운영 및 거래정보 포털 운영, 데이터 가격 산정 가이드라인, 데이터 전문인력 양성 등으로 극복할 수 있다고 설명하고 있습니다.

종합하면 국내 데이터경제의 활성화를 위해서는 첫째, 데이터 활용 촉진을 위한 데이터 경제 거버넌스 구축. 둘째, 데이터 활용 촉진을 위한 공공 및 민간 분야의 최고 데이터분석책임관 제도 도입. 셋째, 민간 수요 확산을 견인할 데이터 경제 생태계 조성. 넷째, 데이터 거래 활성화를 위한 데이터 가격 산정방안 개발 및 확산 방안 구축. 다섯째, 데이터 주도 혁신을 위한 데이터 우선 문화 확산. 여섯째, 데이터 경제 발전을 위한 안전한 데이터 이용환경 구축이 필요합니다.
출처 : 데이터 경제 기반 정책 연구 최종 보고서(4차산업혁명위원회, 2018)

데이터 가치 사실은 가치창출활동, 제품이 개발되고 생산되어 판매되는 일련의 프로세스로 데이터 산업은 데이터를 수집, 인사이트를 도출, 분석결과 이용, 피드백 등 각 단계에 필요한 행위들을 정의하고 관리할 필요가 있습니다.

The Value Chain and Competitive advantage, Free Press, NewYork

데이터 거래 전문가는 어떠한 역할을 할까요?
그림에서와 같이 수집된 다양한 형태의 데이터 즉, 비정형 텍스트, 이미지, 동영상, 음성 데이터 등과 고객의 다양한 정보들, 센서 및 다양한 IoT 기기에서 발생하는 정보들을 결합 및 가공하여 잠재 고객 세그먼트를 생성하여 재판매하는 역할을 수행합니다.

전 세계적으로 약 4,000개 이상의 데이터 중개회사가 존재하며 그 규모도 2,000억 달러에 달합니다. 그러나 이러한 데이터 중개회사를 통한 고객 정보 유출과 같은 개인정보 및 보안 침해 사례가 발생하기도 하여 데이터의 이용과 활용에 법적인 제도 정비가 필요한 실정입니다.

https://clearcode.cc/blog/what-is-data-broker/

우리나라의 경우는 2019년부터 약 10개 분야의 빅데이터 생산/유통을 위한 빅데이터 플랫폼을 구축하고 운영(20년도 5개 분야 추가예정)하고 있습니다. 1차년도의 플랫폼 구축, 2차년도 분야별플랫폼 연계, 3차년도 데이터기반 유통시장확대 추진을 계획하고 있습니다.

국가데이터맵
https://www.data.go.kr/tcs/opd/ndm/view.do

범정부 데이터 플랫폼은 공공기관이 보유한 공공데이터의 소재와 메타데이터 정보를 통합관리하기 위한 목적으로 추진정인 범정부 사업입니다. 공공기관이 활용하는 모든 메타데이터는 기관 메타관리시스템으로 통합관리되고 범정부적 활용을 위해 메터데이터 정보는 용어, 형식을 표준화하여 데이터사전으로 관리됩니다.
범정부 데이터 플랫폼에 수집된 모든 공공데이터는 국가데이터맵을 통해 데이터의 소재 정보 및 연관관계를 시각화된 형식으로 제공됩니다.
범정부 데이터플랫폼의 주요 목표는 데이터 플랫폼 구축, 메터데이터 수집 체계 구축, 메타데이터 관리체계 구축, 국가데이터맵 구축입니다.

국가데이터맵의 개념 및 모델(TTA Journal, 2019)

Google Colab GPU Text-classification

Colaboratory(혹은 Colab)를 사용하면 브라우저에서 Python을 작성하고 실행할 수 있습니다. 장점이라면 별도의 구성이 필요 없고 무료로 GPU를 사용할 수 있다는 장점이 있습니다. 또 만든 코드를 간단하게 공유할 수도 있습니다.

감성분석(Text Classification)에 사용한 데이터는 네이버에서 공개한 영화 평점 정보입니다. 해당 데이터는 아래 링크에서 받을 수 있습니다.
https://github.com/e9t/nsmc

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import io

본 예제에서 사용할 konlpy를 Colab에 설치합니다.

!pip install konlpy
from konlpy.tag import Okt
okt = Okt()

Colab에서 사용할 파일을 사용자 계정의 구글 드라이브에 업로드합니다. 그리고 업로드한 파일 정보를 Colab에서 읽을 수 있도록 필요한 python 라이브러리를 등록해야합니다. 아래 코드를 실행하면 구글 계정에 인증할 수 있는 정보가 나오고 키값을 입력하면 드라이브에 접근할 수 있습니다.

from google.colab import drive
drive.mount('/content/gdrive')

구글 드라이브에 접근이 완료되면 파일이 있는 디렉토리 위치로 이동합니다.

from google.colab import drive
drive.mount('/content/gdrive')
%cd gdrive/My\ Drive/Colab\ Notebooks

해당 위치로 이동한 후에 %ls 명령을 실행시켜보면 해당 폴더에 있는 파일 리스트를 표시해줍니다. 파일 중에서 학습에 사용할 파일을 open하면 됩니다.

%ls
def read_data(filename):
    with io.open(filename, 'r',encoding='utf-8') as f:
        data = [line for line in f.read().splitlines()]
        data = data[1:]
    return data 

sentences = []
# 테스트를 위해 길이가 30 이하인 문장을 읽음
for sentence in read_data('./ratings_test.txt'):
  if len(sentence) <= 30:
    sentences.append(sentence)

해당 파일을 읽어보면 아래와 같은 형태로 데이터가 구성되어 있습니다. 이전 예제에서 설명했던 것처럼 1은 긍정적인 답변을 0은 부정적인 답변을 의미합니다.

['6270596|굳 ㅋ|1',
 '7898805|음악이 주가 된, 최고의 음악영화|1',
 '6315043|진정한 쓰레기|0',
 '7462111|괜찮네요오랜만포켓몬스터잼밌어요|1',
 '10268521|소위 ㅈ문가라는 평점은 뭐냐?|1' ...
class Vocab():
    def __init__(self):
        self.vocab2index = {'<pad>':0,'<unk>':1} # padding 0, unkown 1
        self.index2vocab = {0:'<pad>',1:'<unk>'} # 0 padding, 1 unkown
        self.vocab_count = {}
        self.n_vocab = len(self.vocab2index)
        
    def add_vocab(self, sentence):
        for word in sentence:
            if word not in self.vocab2index:
                self.vocab2index[word] = self.n_vocab
                self.index2vocab[self.n_vocab] = word
                self.vocab_count[word] = 1
                self.n_vocab += 1
            else:
                self.vocab_count[word] += 1

vo = Vocab()

def charStrip(s):
    s = s.replace('"','').replace('「','').replace('」','').replace('“','').replace('?','').replace('”','')
    s = s.replace('(',' ').replace(')',' ').replace('‘','').replace('’','').replace('□','').replace('◆','').replace('◇','')
    s = s.replace('[',' ').replace(']',' ').replace('○','').replace('△','').replace('◎','').replace('▣','').replace('◇','')
    s = s.replace('.',' ').replace('*',' ').replace('.',' ').replace('~',' ')
    
    return s

x = [] # text sentence
y = [] # label
for sentence in sentences:
    arr = sentence.split('|')
    if(len(arr) == 3):
      sentence = okt.morphs(charStrip(arr[1]))
      
      vo.add_vocab(sentence)
      x.append(sentence) 
      y.append(float(arr[2])) 
MAX_SEQUENCE_LENGTH = 0

for sentence in x:
    if MAX_SEQUENCE_LENGTH < len(sentence): MAX_SEQUENCE_LENGTH = len(sentence)

MAX_SEQUENCE_LENGTH

데이터 중에서 가장 긴 문장을 확인해봅니다. 이 문장의 크기가 Sequence Length가 됩니다. 이 문장의 길이보다 작은 문장의 경우 빈칸은 <unk> 값으로 채워줍니다.

def tensorize(vocab, sentence):
    idx = [vocab.vocab2index[word] for word in sentence]
    #return torch.Tensor(idx).long().item()
    return idx

tmp_tensor = []
for sentence in x:
    tmp = tensorize(vo, sentence)
    tmp_zero = np.zeros(MAX_SEQUENCE_LENGTH)
    
    for i,val in enumerate(tmp):
        tmp_zero[i] = val
        
    tmp_tensor.append(tmp_zero)
    
x_data = torch.Tensor(tmp_tensor).long()
y_data = torch.Tensor([float(t) for t in y])
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
output : device(type='cuda')

구글 Colab에서는 GPU를 사용할 수 있기 때문에 필요한 설정을 해줍니다. CPU로 연산할 때보다 훨씬 빠른 계산속도를 보여줍니다.

학습용 데이터는 8/2로 학습용 Train Data / Valid Data 데이터로 나눠줍니다.

DATA_LENGTH = x_data.size(0)

train_cnt = int(DATA_LENGTH*.8)
valid_cnt = DATA_LENGTH - train_cnt
print('train_cnt, valid_cnt = ',train_cnt,valid_cnt)

idx = torch.randperm(DATA_LENGTH)
x_train = torch.index_select(x_data, dim=0, index=idx).to(device).split([train_cnt, valid_cnt], dim=0)
y_train = torch.index_select(y_data, dim=0, index=idx).to(device).split([train_cnt, valid_cnt], dim=0)

각 데이터셋은 pytorch의 Dataset, DataLoader를 사용해서 배치사이즈로 나눠줍니다. 학습할 데이터가 많은 경우에 많은 데이터를 한번에 읽으면 메모리 부족현상이 발생하는데 Dataset을 배치사이즈로 분리해서 로딩하면 메모리를 적게 사용하게 되어 큰 데이터도 학습할 수 있습니다.

from torch.utils.data import Dataset, DataLoader

class SimpanDataset(Dataset):
    
    def __init__(self, data, label):
        super().__init__()
        self.data = data
        self.labels = label
        
    def __len__(self):
        return len(self.data)
    
    def __getitem__(self, idx):
        return self.data[idx], self.labels[idx]
    
# train_loader
train_loader = DataLoader(dataset=SimpanDataset(x_train[0], y_train[0]), batch_size=250, shuffle=True)
valid_loader = DataLoader(dataset=SimpanDataset(x_train[1], y_train[1]), batch_size=250, shuffle=False)

학습용 모델을 아래와 같이 설정합니다. 학습 모델은 Embedding -> BiLSTM -> Softmax 레이어를 통과하면서 최종 output을 만들어냅니다.
단, output은 모든 Sequence의 데이터를 사용하지 않고 마지막 시퀀스의 값만 사용하며 LSTM의 모델에서 bidirectional을 True로 설정했기 때문에 output*2의 값이 리턴됩니다. 학습에 최종 결과물은 0과 1이기 때문에 hidden_size는 2입니다.

class SimpanClassificationModel(nn.Module):
    
    def __init__(self, input_size, hidden_size):
        super().__init__()
        
        self.embedding = nn.Embedding(input_size, 300)
        
        self.rnn = nn.LSTM(input_size=300, hidden_size=100, num_layers=4, batch_first=True, bidirectional=True)
        
        self.layers = nn.Sequential(
            nn.ReLU(),
            nn.Linear(100*2,100),
            nn.Linear(100,30),
            
            nn.Linear(30, hidden_size),
        )
        
        self.softmax = nn.Softmax(dim=-1)
        
    def forward(self, x):
        y = self.embedding(x)
        y,_ = self.rnn(y)
        y = self.layers(y)
        
        return self.softmax(y[:,-1,:])
    
input_size = vo.n_vocab
hidden_size = torch.unique(y_train[1]).size(dim=-1)

model = SimpanClassificationModel(input_size, hidden_size)
model = model.cuda()
# loss & optimizer setting
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters())

hist_loss = []
hist_accr = []

epochs = 501
# start training
model.train()

for epoch in range(epochs):
    epoch_loss = 0
    for x,y in train_loader:
      x, y = x.to(device), y.to(device)
      output = model(x)
      loss = criterion(output, y.long())
        
      optimizer.zero_grad()
      loss.backward()
      optimizer.step()
        
      epoch_loss += loss.item()
      accuracy = (torch.argmax(output, dim=-1) == y).float().mean().item()
    
      
    hist_loss.append(epoch_loss)
    hist_accr.append(accuracy)
        
    print('Cost: {:.6f}, Accuracy : {:.6f}'.format(loss.item(),accuracy))
    print('--{}--'.format(epoch))

학습의 진행상황을 기록하기 위해서 2개의 배열(hist_loss, hist_accr)을 사용합니다.

hist_loss는 loss값의 변화를 기록하는 배열이며 hist_accr은 해당 모델의 정확도 정보를 얻기 위해서 만든 배열입니다. 학습이 진행되며 해당 배열에 데이터가 기록되고 matplotlib.pyplot을 사용해서 그래프를 그려봅니다.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(2,1)
fig.set_size_inches((12, 8)) 

ax[0].set_title('Loss')
ax[0].plot(hist_loss, color='red')
ax[0].set_ylabel('Loss')
ax[1].set_title('Accuracy')
ax[1].plot(hist_accr, color='blue')
ax[1].set_ylabel('Accuracy')
ax[1].set_xlabel('Epochs')

plt.show()
model.eval()
    
for xv, yv in valid_loader:
    output = model(x)
    
    accuracy = (torch.argmax(output, dim=-1) == y).float().mean().item()

    hist_loss.append(loss.item())
    hist_accr.append(accuracy)

    print('Accuracy : {:.6f}'.format(accuracy))

모델의 학습이 완료된 후 valid data를 통해서 학습 모델의 정확도를 알아봅니다.

Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667
Accuracy : 0.916667