이번 포스팅에서는 (1) text 또는 csv 포맷으로 저장된 텍스트 파일을 Python의 string methods 를 사용하여 파일을 열어서 파싱하여 matrix 로 저장하고,  (2) 숫자형 데이터를 표준화(standardization) 혹은 정규화(normalization) 하는 사용자 정의함수를 만들어보겠습니다. 

 

예제로 사용할 text 파일은 전복의 성별과 length, diameter, height, whole_weight, shucked_weight, viscera_weight, shell_weight, rings 를 측정한 abalone.txt 파일 입니다. 

abalone.txt
0.18MB

1. text 파일을 읽어서 숫자형 값으로 만든 matrix, 라벨을 저장한 vector를 만들기

물론, Pandas 모듈의 read_csv() 함수를 이용하여 편리하게 text, csv 포맷의 파일을 읽어올 수 있습니다. 

# importing modules
import numpy as np
import pandas as pd
import os

# setting directory
base_dir = '/Users/ihongdon/Documents/Python'
work_dir = 'dataset'
path = os.path.join(base_dir, work_dir)

# reading text file using pandas read_csv() function
df = pd.read_csv(os.path.join(path, 'abalone.txt'), 
                 sep=',', 
                 names=['sex', 'length', 'diameter', 'height', 'whole_weight', 
                        'shucked_weight', 'viscera_weight', 'shell_weight', 'rings'], 
                 header=None)
                 
# check first 5 lines
df.head()
sex	length	diameter	height	whole_weight	shucked_weight	viscera_weight	shell_weight	rings
0	M	0.455	0.365	0.095	0.5140	0.2245	0.1010	0.150	15
1	M	0.350	0.265	0.090	0.2255	0.0995	0.0485	0.070	7
2	F	0.530	0.420	0.135	0.6770	0.2565	0.1415	0.210	9
3	M	0.440	0.365	0.125	0.5160	0.2155	0.1140	0.155	10
4	I	0.330	0.255	0.080	0.2050	0.0895	0.0395	0.055	7

 

 

위의 Pandas 의 함수 말고, 아래에는 Python의 string methods 를 사용해서 파일을 열고, 파싱하는 간단한 사용자 정의함수를 직접 만들어보았습니다.

위의 abalone.txt 파일의 데이터 형태를 참고해서 파일 이름, 숫자형 변수의 개수, 숫자형 변수의 시작 위치, 숫자형 변수의 끝나는 위치, 라벨 변수의 우치를 인자로 받는 사용자 정의함수를 정의하였습니다. 분석을 하려는 각 데이터셋에 맞게 인자와 함수 code block 을 수정하면 좀더 유연하고 데이터 특성에 적합하게 파일을 불어올 수 있는 사용자 정의함수를 만들 수 있습니다. 

def file2matrix(filename, val_col_num, val_col_st_idx, val_col_end_idx, label_idx):
    """
    - filename: directory and file name
    - val_col_num: the number of columns which contains numeric values
    - val_col_st_idx: the index of starting column which contains numeric values
    - val_col_end_idx: the index of ending column which contains numeric values
    - label_idx: the index of label column
    """
    # open file
    file_opened = open(filename)
    lines_num = len(file_opened.readlines())
    
    # blank matrix and vector to store
    matrix_value = np.zeros((lines_num, val_col_num))
    vector_label = []
    
    # splits and appends value and label using for loop statement
    file_opened = open(filename)
    idx = 0
    for line in file_opened.readlines():
        # removes all whitespace in string
        line = line.strip()
        
        # splits string according to delimiter str
        list_from_line = line.split(sep=',')
        
        # appends value to matrix and label to vector
        matrix_value[idx, :] = list_from_line[val_col_st_idx : (val_col_end_idx+1)]
        vector_label.append(list_from_line[label_idx])
        idx += 1
        
    return matrix_value, vector_label

 

Python의 문자열 메소드 (string methods)는 https://rfriend.tistory.com/327 를 참고하세요. 

 

위의 file2matrix() 사용자 정의 함수를 사용하여 abalone.txt 파일을 읽어와서 (a) matrix_value, (b) vector_label 을 반환하여 보겠습니다. 

# run file2matrix() UDF
matrix_value, vector_label = file2matrix(os.path.join(path, 'abalone.txt'), 8, 1, 8, 0)

#--- matrix_value
# type
type(matrix_value)
numpy.ndarray

# shape
matrix_value.shape
(4177, 8)

# samples
matrix_value[:3]
array([[ 0.455 ,  0.365 ,  0.095 ,  0.514 ,  0.2245,  0.101 ,  0.15  , 15.    ],
       [ 0.35  ,  0.265 ,  0.09  ,  0.2255,  0.0995,  0.0485,  0.07  ,  7.    ],
       [ 0.53  ,  0.42  ,  0.135 ,  0.677 ,  0.2565,  0.1415,  0.21  ,  9.    ]])
       
#--- vector_label
# type
type(vector_label)
list

# number of labels
len(vector_label)
4177

# samples
vector_label[:3]
['M', 'M', 'F']

 

 

2-1. 숫자형 데이터를 표준화(Standardization) 하기

위의 숫자형 데이터로 이루어진 matrix_value 를 numpy를 이용해서 표준화, 정규화하는 사용자 정의함수를 작성해보겠습니다. (물론 scipy.stats 의 zscore() 나 sklearn.preprocessing 의 StandardScaler() 함수를 사용해도 됩니다.)

 

아래의 사용자 정의 함수는 숫자형 데이터로 이루어진 데이터셋을 인자로 받으면, 평균(mean)과 표준편차(standard deviation)를 구하고, standardized_value = (x - mean) / standard_deviation 으로 표준화를 합니다. 그리고 표준화한 matrix, 각 칼럼별 평균과 표준편차를 반환합니다. 

def standardize(numeric_dataset):

    # standardized_value = (x - mean)/ standard_deviation
    
    # calculate mean and standard deviation per numeric columns
    mean_val = numeric_dataset.mean(axis=0)
    std_dev_val = numeric_dataset.std(axis=0)
    
    # standardization
    matrix_standardized = (numeric_dataset - mean_val)/ std_dev_val
    
    return matrix_standardized, mean_val, std_dev_val

 

위의 standardize() 함수를 사용하여 matrix_value 다차원배열을 표준화해보겠습니다. 

# rund standardize() UDF
matrix_standardized, mean_val, std_dev_val = standardize(matrix_value)

# matrix after standardization
matrix_standardized
array([[-0.57455813, -0.43214879, -1.06442415, ..., -0.72621157,
        -0.63821689,  1.57154357],
       [-1.44898585, -1.439929  , -1.18397831, ..., -1.20522124,
        -1.21298732, -0.91001299],
       [ 0.05003309,  0.12213032, -0.10799087, ..., -0.35668983,
        -0.20713907, -0.28962385],
       ...,
       [ 0.6329849 ,  0.67640943,  1.56576738, ...,  0.97541324,
         0.49695471, -0.28962385],
       [ 0.84118198,  0.77718745,  0.25067161, ...,  0.73362741,
         0.41073914,  0.02057072],
       [ 1.54905203,  1.48263359,  1.32665906, ...,  1.78744868,
         1.84048058,  0.64095986]])
 
 # mean per columns
 mean_val
 array([0.5239921 , 0.40788125, 0.1395164 , 0.82874216, 0.35936749,
       0.18059361, 0.23883086, 9.93368446])
       
 # standard deviation per columns
 std_dev_val
 array([0.12007854, 0.09922799, 0.04182205, 0.49033031, 0.22193638,
       0.10960113, 0.13918601, 3.22378307])

 

2-2. 숫자형 데이터를 정규화(Normalization) 하기

다음으로 척도, 범위가 다른 숫자형 데이터를 [0, 1] 사이의 값으로 변환하는 정규화(Normalization)를 해보겠습니다. normalized_value = (x - minimum_value) / (maximum_value - minimum_value) 로 계산합니다. 

def normalize(numeric_dataset):
    
    # normalized_value = (x - minimum_value) / (maximum_value - minimum_value)
    
    # calculate mean and standard deviation per numeric columns
    min_val = numeric_dataset.min(axis=0)
    max_val = numeric_dataset.max(axis=0)
    ranges = max_val - min_val
    
    # normalization, min_max_scaling
    matrix_normalized = (numeric_dataset - min_val)/ ranges
    
    return matrix_normalized, ranges, min_val

 

위의 normalize() 사용자 정의 함수에 matrix_value 다차원배열을 적용해서 정규화 변환을 해보겠습니다. 정규화된 다차원배열과 범위(range = max_val - min_val), 최소값을 동시에 반환합니다. 

# run normalize() UDF
matrix_normalized, ranges, min_val = normalize(matrix_value)

# normalized matrix
matrix_normalized
array([[0.51351351, 0.5210084 , 0.0840708 , ..., 0.1323239 , 0.14798206,
        0.5       ],
       [0.37162162, 0.35294118, 0.07964602, ..., 0.06319947, 0.06826109,
        0.21428571],
       [0.61486486, 0.61344538, 0.11946903, ..., 0.18564845, 0.2077728 ,
        0.28571429],
       ...,
       [0.70945946, 0.70588235, 0.18141593, ..., 0.37788018, 0.30543099,
        0.28571429],
       [0.74324324, 0.72268908, 0.13274336, ..., 0.34298881, 0.29347285,
        0.32142857],
       [0.85810811, 0.84033613, 0.17256637, ..., 0.49506254, 0.49177877,
        0.39285714]])
        
# ranges
ranges
array([ 0.74  ,  0.595 ,  1.13  ,  2.8235,  1.487 ,  0.7595,  1.0035,  28.    ])

# minimum value
min_val
array([7.5e-02, 5.5e-02, 0.0e+00, 2.0e-03, 1.0e-03, 5.0e-04, 1.5e-03, 1.0e+00])

 

다음번 포스팅에서는 텍스트 파일을 파싱해서 One-Hot Encoding 하는 방법을 소개하겠습니다. 

 

많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

CNN(Convolutional Neural Network)으로 이미지 분류 모델링할 때 보통 tensorflow나 keras 라이브러리에 이미 포함되어 있는 MNIST, CIFAR-10 같은 이미지를 간단하게 load 하는 함수를 이용해서 toy project로 연습을 해보셨을 겁니다. 

그런데, 실제 이미지, 그림 파일을 분석해야 될 경우 '어? 이미지를 어떻게 업로드 하고, 어떻게 전처리하며, 어떻게 시각화해야 하는거지?'라는 의문을 한번쯤은 가져보셨을 듯 합니다. 

이번 포스팅에서는 바로 이 의문에 대한 답변 소개입니다. 


필요한 Python 라이브러리를 불러오겠습니다. 

 import numpy as np

 import pandas as pd

 import matplotlib.pyplot as plt

 import keras 



 1. 개와 고양이 사진 다운로드 (download dogs and cats images from Kaggle)

개와 고양이 사진을 아래의 Kaggle 사이트에서 다운로드 해주세요. Kaggle 회원가입을 먼저 해야지 다운로드 할 수 있습니다. 개는 1, 고양이는 0으로 라벨링이 되어 있는 25,000 개의 이미지를 다운받을 수 있습니다. 

https://www.kaggle.com/c/dogs-vs-cats/data



2. 개와 고양이 이미지 30개만 선택해서 별도 경로(폴더)에 복사하기


downloads 폴더에 들어있는 압축된 다운로드 파일을 압축 해제(unzip)해 주세요. 


윈도우 탐색기로 미리보기를 해보면 고양이 반, 개 반 입니다. 


directory, path 관리하는데 필요한 os 라이브러리, 파일을 source에서 destination 경로로 복사하는데 필요한 shutil 라이브러리를 불러오겠습니다. 

 import os # miscellaneous operating system interfaces

 import shutil # high-level file operations


이미지를 가져올 경로를 설정해보겠습니다. ('Downdoads/dogs-vs-cats/train' 경로에 train 폴더를 압축해제해 놓았습니다. 폴더 경로 확인 요함.)

# The path to the directory where the original dataset was uncompressed

 base_dir = '/Users/admin/Downloads'

 img_dir = '/Users/admin/Downloads/dogs-vs-cats/train'


train 폴더에 들어있는 개와 고양이 이미지가 총 25,000개 임을 확인했으며,  img_dir 경로에 포함되어 있는 이미지 중에서 10개만 indexing 해서 파일 제목을 확인해보았습니다. 

 len(os.listdir(img_dir))

 25000

os.listdir(img_dir)[:10]

['dog.8011.jpg',
 'cat.5077.jpg',
 'dog.7322.jpg',
 'cat.2718.jpg',
 'cat.10151.jpg',
 'cat.3406.jpg',
 'dog.1753.jpg',
 'cat.4369.jpg',
 'cat.7660.jpg',
 'dog.5535.jpg']


30개의 이미지만 샘플로 선별해서 다른 폴더로 복사해보겠습니다. 먼저, 30개 고양이 이미지를 담아둘 경로/ 폴더(cats30_dir) 를 만들어보겠습니다. 

# Directory with 30 cat pictures

 cats30_dir = os.path.join(base_dir, 'cats30')


 # Make a path directory

 os.mkdir(cats30_dir)


이제 source 경로에서 destination 경로로 shutil.copyfile(src, dst) 함수를 사용하여 고양이 이미지 30개만 이미지를 복사하겠습니다.  

# Copy first 30 cat images to cats30_dir

 fnames = ['cat.{}.jpg'.format(i) for i in range(30)]

 

 for fname in fnames:

     src = os.path.join(img_dir, fname)

     dst = os.path.join(cats30_dir, fname)

     shutil.copyfile(src, dst)


cats30_dir 경로로 복사한 30개의 고양이 이미지 파일 목록을 확인해 보았습니다. 

# check if pictures were copied well in cats30 directory

 os.listdir(cats30_dir)

['cat.6.jpg',
 'cat.24.jpg',
 'cat.18.jpg',
 'cat.19.jpg',
 'cat.25.jpg',
 'cat.7.jpg',
 'cat.5.jpg',
 'cat.27.jpg',
 'cat.26.jpg',
 'cat.4.jpg',
 'cat.0.jpg',
 'cat.22.jpg',
 'cat.23.jpg',
 'cat.1.jpg',
 'cat.3.jpg',
 'cat.21.jpg',
 'cat.20.jpg',
 'cat.2.jpg',
 'cat.11.jpg',
 'cat.10.jpg',
 'cat.12.jpg',
 'cat.13.jpg',
 'cat.9.jpg',
 'cat.17.jpg',
 'cat.16.jpg',
 'cat.8.jpg',
 'cat.28.jpg',
 'cat.14.jpg',
 'cat.15.jpg',
 'cat.29.jpg']



 3. 이미지 파일을 로딩, float array 로 변환 후 전처리하기
    (load image file and convert image data to float array format) 

Keras preprocessing 에 있는 image 클래스를 불러온 후, load_img() 함수를 사용해서 이미지 파일을 로딩하고, img_to_array() 함수를 사용해서 array 로 변환해보겠습니다. (Python OpenCV 라이브러리로도 가능함)

# a picture of one cat as an example

 img_name = 'cat.10.jpg'

 img_path = os.path.join(cats30_dir, img_name)


 # Preprocess the image into a 4D tensor using keras.preprocessing

 from keras.preprocessing import image


 img = image.load_img(img_path, target_size=(250, 250))

 img_tensor = image.img_to_array(img)


3차원 array에 이미지 샘플을 구분할 수 있도록 np.expand_dims() 함수를 사용하여 1개 차원을 추가하겠습니다. 그리고 [0, 1] 값 범위 내에 값이 존재하도록 array 값을 255.로 나누어서 표준화해주었습니다. 

  # expand a dimension (3D -> 4D)

 img_tensor = np.expand_dims(img_tensor, axis=0)

 img_tensor.shape

 (1, 250, 250, 3)

 

 # scaling into [0, 1]

 img_tensor /= 255.


첫번째 고양이 이미지의 array 데이터를 출력해보면 아래처럼 생겼습니다. 꼭 영화 메트릭스의 숫자들이 주루룩 내려오는 장면 같이 생겼습니다. 

img_tensor[0]

array([[[0.10196079, 0.11764706, 0.15294118],
        [0.07450981, 0.09019608, 0.1254902 ],
        [0.03137255, 0.04705882, 0.09019608],
        ...,
        [0.5058824 , 0.6313726 , 0.61960787],
        [0.49411765, 0.61960787, 0.60784316],
        [0.49019608, 0.6156863 , 0.6039216 ]],

       [[0.11764706, 0.13333334, 0.16862746],
        [0.13725491, 0.15294118, 0.1882353 ],
        [0.08627451, 0.10196079, 0.13725491],
        ...,
        [0.50980395, 0.63529414, 0.62352943],
        [0.49803922, 0.62352943, 0.6117647 ],
        [0.4862745 , 0.6117647 , 0.6       ]],

       [[0.11372549, 0.14117648, 0.16470589],
        [0.16470589, 0.19215687, 0.22352941],
        [0.15294118, 0.18039216, 0.21176471],
        ...,
        [0.50980395, 0.63529414, 0.62352943],
        [0.5019608 , 0.627451  , 0.6156863 ],
        [0.49019608, 0.6156863 , 0.6039216 ]],

       ...,

       [[0.69411767, 0.6431373 , 0.46666667],
        [0.6862745 , 0.63529414, 0.45882353],
        [0.6627451 , 0.6117647 , 0.4392157 ],
        ...,
        [0.7254902 , 0.70980394, 0.04313726],
        [0.6745098 , 0.6509804 , 0.03921569],
        [0.64705884, 0.6156863 , 0.05490196]],

       [[0.64705884, 0.5921569 , 0.45490196],
        [0.6117647 , 0.5568628 , 0.4117647 ],
        [0.5686275 , 0.5176471 , 0.3529412 ],
        ...,
        [0.7254902 , 0.7137255 , 0.01960784],
        [0.6862745 , 0.67058825, 0.00784314],
        [0.6509804 , 0.6313726 , 0.        ]],

       [[0.6039216 , 0.54901963, 0.4117647 ],
        [0.5882353 , 0.53333336, 0.3882353 ],
        [0.5803922 , 0.5294118 , 0.3647059 ],
        ...,
        [0.7254902 , 0.7137255 , 0.01960784],
        [0.6862745 , 0.67058825, 0.00784314],
        [0.6509804 , 0.6313726 , 0.        ]]], dtype=float32)



  4. 한개의 이미지 파일의 array 를 시각화하기 (visualizing an image array data)

matplotlib 라이브러리를 이용하여 위의 3번에서 이미지의 array 변환/ 전처리한 데이터를 시각화해보겠습니다. 예제로서 img_tensor[0] 으로 첫번째 고양이 이미지의 데이터를 시각화했습니다. 

# Image show

 import matplotlib.pyplot as plt

 plt.rcParams['figure.figsize'] = (10, 10) # set figure size

 

 plt.imshow(img_tensor[0])

 plt.show()




  5. 30개의 이미지 데이터를 6*5 격자에 나누어서 시각화하기 
    (visualizing 30 image data at 6*5 grid layout)

위의 3번에서 했던 이미지 파일 로딩, array로 변환, 1개 차원 추가, [0, 1] 범위로 표준화하는 전처리를 preprocess_img() 라는 이름의 사용자정의함수(UDF)로 만들었습니다. 

# UDF of pre-processing image into a 4D tensor

 def preprocess_img(img_path, target_size=100):

     from keras.preprocessing import image

     

     img = image.load_img(img_path, target_size=(target_size, target_size))

     img_tensor = image.img_to_array(img)

    

     # expand a dimension

     img_tensor = np.expand_dims(img_tensor, axis=0)

     

     # scaling into [0, 1]

     img_tensor /= 255.

     

     return img_tensor


이제 30개의 고양이 이미지 array 데이터를 사용해서 행(row) 6개 * 열(column) 5개의 격자 배열(grid layout) 에 시각화를 해보겠습니다. 이때 가독성을 높이기 위해서 고양이 사진 간에 검정색 구분선을 넣어서 시각화를 해보겠습니다. 

참고로, 아래 코드의 for loop 중간에 방금 전에 위에서 정의한 preprocess_img() 사용자정의함수 (빨간색으로 표기) 가 사용되었습니다. 

# layout

n_pic = 30

n_col = 5

n_row = int(np.ceil(n_pic / n_col))


# plot & margin size

target_size = 100

margin = 3


# blank matrix to store results

total = np.zeros((n_row * target_size + (n_row - 1) * margin, n_col * target_size + (n_col - 1) * margin, 3))


# append the image tensors to the 'total matrix'

img_seq = 0


for i in range(n_row):

    for j in range(n_col):


        fname = 'cat.{}.jpg'.format(img_seq)

        img_path = os.path.join(cats30_dir, fname)


        img_tensor = preprocess_img(img_path, target_size)


        horizontal_start = i * target_size + i * margin

        horizontal_end = horizontal_start + target_size

        vertical_start = j * target_size + j * margin

        vertical_end = vertical_start + target_size


        total[horizontal_start : horizontal_end, vertical_start : vertical_end, :] = img_tensor[0]

        

        img_seq += 1


# display the pictures in grid

plt.figure(figsize=(200, 200))

plt.imshow(total)

plt.show()


많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. 


Posted by R Friend R_Friend

이번 포스팅에서는 os 라이브러리를 이용한 경로 및 폴더 관리, shutil 라이브러리를 이용한 파일 복사 방법에 대한 소소한 팁들을 소개하겠습니다. 

os 라이브러리에 대해서 소개해 놓은 페이지 ( https://docs.python.org/3/library/os.html )에 가보면 '기타 운영 체계에 대한 인터페이스 (Miscellaneous operating system interfaces)' 라고 소개를 하면서 스크롤 압박에 굉장히 심할 정도로 여러개의 함수들을 소개해 놓았습니다. 

그 많은 것을 모두 소개하기는 힘들구요, 그중에서도 이번 포스팅에서는 제가 자주 쓰는 함수들만 몇 개 선별해서 소개하도록 하겠습니다. 


  1. os 라이브러리를 이용한 경로 및 폴더 관리


먼저 os 라이브러리를 불러오겠습니다. 


import os # Miscellaneous operating system interfaces



1-1. 현재 작업경로 확인하기: os.getcwd()


# os.getcwd(): returns the current working directory

os.getcwd()

'C:\\Users\\admin\\python'

 



1-2. 작업경로 안에 들어있는 파일 리스트 확인하기: os.listdir(path)


# os.listdir(path): return a list of then entries in the directory given by path

os.listdir(os.getcwd()) # a list of files at current directory

['.ipynb_checkpoints', 'numpy_adding_new_axis.ipynb', 'Numpy_clip.ipynb', 'python_os.ipynb'] 




1-3. 작업경로 바꾸기: os.chdir(path)


# os.chdir(path): change the current working directory to path

base_dir = 'C:/Users/admin'

os.chdir(base_dir)

os.getcwd()

 'C:\\Users\\admin'




1-4. 기존 경로와 새로운 폴더 이름을 합쳐서 하위 경로 만들기: os.path.join()


# join one or more path components

path = os.path.join(base_dir, 'os')

path

'C:/Users/admin\\os'




1-5. 새로운 폴더를 만들기: os.mkdir(path)

 

# create a directory named path with numeric mode

os.mkdir(path)




1-6. 경로가 존재하는지 확인하기: os.path.isdor(path)


# return True if path is an existing directory

os.path.isdir(path)

True

 



1-7. 파일이나 경로 이름 바꾸기: os.rename(old_path_name, new_path_name)


# rename the file or directory src to dst

# os.rename(src, dst)

dst_path = os.path.join(base_dir, 'os_renamed')

os.rename(path, dst_path)

os.path.isdir(dst_path) # check whether dst_path is renamed or not

True

 



1-8. 경로(폴더) 제거하기: os.rmdir(path)

단, 폴더 안에 파일이 없어야지 os.rmdir()을 사용할 수 있습니다. 


# remove 

os.rmdir(dst_path)

os.path.isdir(dst_path) # check whether dst_path is removed or not

False

 



  2. shutil 라이브러리를 이용한 파일 복사: shutil.copyfile(src, dst)


먼저, 파일을 복사해올 소스 경로(source directory, from)와 파일을 복사해놓은 종착지 경로(destination directory, to)를 만들어보겠습니다. 


# creating src_dir, dst_dir

base_dir = 'C:/Users/admin'

src_dir = os.path.join(base_dir, 'src_dir')

dst_dir = os.path.join(base_dir, 'dst_dir')


os.mkdir(src_dir)

os.mkdir(dst_dir)

 


다음으로, 소스 경로(src_dir)에 'file_1.txt', 'file_2.txt', 'file_3.txt' 라는 이름으로 메모장으로 작성한 간단한 텍스트 파일 3개를 저장해두었습니다. (직접 수작업으로 메모장 열고 문자 몇개 입력하고 저장함)

os.listdir() 를 사용하여 소스 경로(src_dir)에 들어있는 3개의 텍스트파일 이름을 fnames 라는 이름의 리스트로 만들어두었습니다. 


# put file_1, file_2, file_3 into src_dir

fnames = os.listdir(src_dir)

fnames

['file_1.txt', 'file_2.txt', 'file_3.txt'] 



마지막으로, shutil 라이브러리를 불러오고, shutil.copyfile(src, dst) 함수를 사용하여 소스 경로(source directory)에 들어있는 3개의 텍스트 파일을 종착지 경로(destination directory)로 복사해보겠습니다. 

이때 for loop 문을 사용하여 텍스트 파일 별로 shutil.copyfile(src, dst)를 적용해주면 됩니다. 


# copy files from src to dst directory

import shutil


for fname in fnames:

    src = os.path.join(src_dir, fname)

    dst = os.path.join(dst_dir, fname)

    shutil.copyfile(src, dst)


os.listdir(dst_dir)

['file_1.txt', 'file_2.txt', 'file_3.txt'] 



많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)

Posted by R Friend R_Friend

이번 포스팅에서는 Python Numpy 배열 (array)에 차원을 추가하는 3가지 방법을 소개하겠습니다. 딥러닝 공부하다 보면 computer vision의 CNN에서 이미지 파일을 불러와서 다차원 배열로 변환할 때 사용하곤 합니다. 

1. numpy.reshape() 을 이용한 차원 추가

2. numpy.expand_dims() 을 이용한 차원 추가

3. numpy.newaxis 을 이용한 차원 추가


예제로 사용할 간단한 (4, 3, 2) 3차원의 다차원 배열을 만들어보겠습니다. 


import numpy as np

a = np.arange(24).reshape(4, 3, 2)

a

array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],

       [[ 6,  7],
        [ 8,  9],
        [10, 11]],

       [[12, 13],
        [14, 15],
        [16, 17]],

       [[18, 19],
        [20, 21],
        [22, 23]]])

a.shape

(4, 3, 2)




(4, 3, 2) 차원의 배열 a에 차원을 추가하여 (1, 4, 3, 2)의 4차원 배열로 만들어보겠습니다. 


  1. numpy.reshape() 를 이용한 차원 추가


 

np.reshape(a, (1, 4, 3, 2))

array([[[[ 0,  1],
         [ 2,  3],
         [ 4,  5]],

        [[ 6,  7],
         [ 8,  9],
         [10, 11]],

        [[12, 13],
         [14, 15],
         [16, 17]],

        [[18, 19],
         [20, 21],
         [22, 23]]]])


 np.reshape(a, ((1,) + a.shape))

array([[[[ 0,  1],
         [ 2,  3],
         [ 4,  5]],

        [[ 6,  7],
         [ 8,  9],
         [10, 11]],

        [[12, 13],
         [14, 15],
         [16, 17]],

        [[18, 19],
         [20, 21],
         [22, 23]]]])

 a.reshape((1,) + a.shape)

array([[[[ 0,  1],
         [ 2,  3],
         [ 4,  5]],

        [[ 6,  7],
         [ 8,  9],
         [10, 11]],

        [[12, 13],
         [14, 15],
         [16, 17]],

        [[18, 19],
         [20, 21],
         [22, 23]]]])



  2. numpy.expand_dims() 를 이용한 차원 추가



np.expand_dims(a, axis=0)

array([[[[ 0,  1],
         [ 2,  3],
         [ 4,  5]],

        [[ 6,  7],
         [ 8,  9],
         [10, 11]],

        [[12, 13],
         [14, 15],
         [16, 17]],

        [[18, 19],
         [20, 21],
         [22, 23]]]])

 



  3. numpy.newaxis 를 이용한 차원 추가



a[:, np.newaxis]

array([[[[ 0,  1],
         [ 2,  3],
         [ 4,  5]]],


       [[[ 6,  7],
         [ 8,  9],
         [10, 11]]],


       [[[12, 13],
         [14, 15],
         [16, 17]]],


       [[[18, 19],
         [20, 21],
         [22, 23]]]])

 


많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)

Posted by R Friend R_Friend

이번 포스팅에서는 배열(array)에서 0보다 작은 수는 0으로 변환하고 나머지는 그대로 두는 여러가지 방법을 소개하겠습니다. 


1. List Comprehension with for loop

2. Indexing

3. np.where(condition[, x, y])

4. np.clip(a, a_min, a_max, out=None)





  1. List Comprehension: [0 if i < 0 else i for i in a]


아래처럼 for loop 을 써서 list comprehension 방법을 사용하면 특정 라이브러리의 함수를 사용하지 않아도 0보다 작은 수는 0으로 변환할 수 있습니다. 하지만, for loop 을 돌기 때문에 배열(array)가 커지면 성능이 문제될 수 있습니다.  원래의 배열 a는 그대로 있습니다. 



>>> import numpy as np

>>> a = np.arange(-5, 5)

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

>>> [0 if i < 0 else i for i in a]

[0, 0, 0, 0, 0, 0, 1, 2, 3, 4]

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])





  2. Indexing: a[a < 0] = 0


아래처럼 indexing을 사용해서 a[a < 0] = 0 처럼 0보다 작은 값이 위치한 곳에 0을 직접 할당할 수 있습니다. 이렇게 하면 원래의 배열 a가 변경됩니다. 



>>> a = np.arange(-5, 5)

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

>>> a[a < 0] = 0

>>> a

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

 




  3. np.where() : np.where(a < 0, 0, a)


np.where(조건, True일 때 값, False일 때 값) 를 사용하면 편리하게 0보다 작은 조건의 위치에 0을 할당할 수 있습니다. 벡터 연산을 하므로 for loop이 돌지 않아서 속도가 매우 빠릅니다. 원래의 배열 a는 변경되지 않고 그대로 있습니다. 



>>> a = np.arange(-5, 5)

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

>>> np.where(a < 0, 0, a)

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

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

 



만약 0보다 작은 수는 0으로 변환, 2보다 큰 수는 2로 변환하고 싶다면 아래처럼 np.where() 안에 np.where()를 한번 더 넣어서 써주면 되는데요, 코드가 좀 복잡해보입니다. 



>>> a = np.arange(-5, 5)

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

>>>

>>> np.where(a < 0, 0, np.where(a > 2, 2, a))

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

 




  4. np.clip() : np.clip(a, 0, 4, out=a)


np.clip(배열, 최소값 기준, 최대값 기준) 을 사용하면 최소값과 최대값 조건으로 값을 기준으로 해서, 이 범위 기준을 벗어나는 값에 대해서는 일괄적으로 최소값, 최대값으로 대치해줄 때 매우 편리합니다. 최소값 부분을 0으로 해주었으므로 0보다 작은 값은 모두 0으로 대치되었습니다. 이때 원래의 배열 a는 그대로 있습니다. 



>>> a = np.arange(-5, 5)

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

>>> np.clip(a, 0, 4)

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

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

 



np.clip(배열, 최소값 기준, 최대값 기준, out 배열)을 사용해서 out = a 를 추가로 설정해주면 반환되는 값을 배열 a에 저장할 수 있습니다. 배열 a의 0보다 작았던 부분이 모두 0으로 대치되어 a가 변경되었음을 확인할 수 있습니다. 



>>> np.clip(a, 0, 4, out=a)

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

>>> a

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

 



최소값 기준만 적용해서 간단하게 '0'보다 작은 수는 모두 0으로 바꾸는 것은 a.clip(0) 처럼 메소드를 사용해도 됩니다. 



>>> a = np.arange(-5, 5)

>>> a

array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

>>> a.clip(0)

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

 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^^



Posted by R Friend R_Friend

Tensorflow, Keras를 사용하는 중에 'TypeError: softmax() got an unexpected keyword argument 'axis' 의 TypeError 발생 시 업그레이드를 해주면 해결할 수 있습니다. (저는 Python 2.7 버전, Tensorflow 1.4 버전 사용 중에 Keras로 softmax() 하려니 아래의 에러 발생하였습니다)





먼저, 명령 프롬프트 창에서 Tensorflow 가 설치된 conda environment 를 활성화시켜보겠습니다. 



$ conda env list

tensorflow     /Users/myid/anaconda3/envs/tensorflow


$ source activate tensorflow  # for mac OS

$ activate tensorflow # for Windows OS


(tensorflow) $ 

 




참고로 Python과 Tensorflow 버전 확인하는 방법은 아래와 같습니다. 



(tensorflow) $ python -V

Python 2.7.14 :: Anaconda custom (64-bit)


(tensorflow) $ python

Python 2.7.14 |Anaconda custom (640bit)| (default, Oct 5 2017, 02:28:52)

[GCC 4.2.1. Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin

Type "help", "copyright", "credits" ro "license" for more information.

>>> import tensorflow as tf

>>> tf.VERSION

'1.4.0'

 




  (1) TypeError: softmax() got an unexpected keyword argument 'axis' 에러 대처법


Python에서 패키지 관리할 때 사용하는 pip 를 먼저 upgrade 시켜 준 후에 Tensorflow 를 업그레이트 해줍니다. Python 3.n 버전에서는 pip3 install package_name 을 사용하구요, GPU 의 경우 tensorflow-gpu 처럼 뒤에 -gpu를 추가로 붙여줍니다. 



# --------------------
# TypeError: softmax() got an unexpected keyword argument 'axis'
# --------------------

# => upgrade tensorflow to the latest version


(tensorflow)$ pip install pip --upgrade # for Python 2.7
(tensorflow)$ pip3 install pip --upgrade # for Python 3.n

(tensorflow)$ pip install tensorflow --upgrade # for Python 2.7
(tensorflow)$ pip3 install tensorflow --upgrade # for Python 3.n
(tensorflow)$ pip install tensorflow-gpu --upgrade # for Python 2.7 and GPU

(tensorflow)$ pip3 install tensorflow-gpu --upgrade # for Python 3.n and GPU

 




Tensorflow 업그레이드 해줬더니 이번에는 numpy에서 아래의 에러가 나네요, 그래서 numpy도 업그레이드 해주었더니 문제가 해결되었습니다. 


  (2) numpy Traceback (most recent call last) RuntimeError: 

      module compiled against API version 0xc but this version of numpy is 0xb



# --------------
# Traceback (most recent call last) RuntimeError:

# module compiled against API version 0xc but this version of numpy is 0xb
# ---------------


# => upgrade numpy to the latest version


(tensorflow)$ pip install numpy --upgrade



많은 도움이 되었기를 바랍니다. 



Posted by R Friend R_Friend

Plotly는 퀘벡 몬트리올에 본사가 있는 온라인 데이터 분석과 시각화 툴을 개발하는 테크 회사의 이름이기도 하구요, 분석/ 시각화 라이브러리의 이름이기도 합니다. Plotly 툴은 Python과 Django 프레임워크를 사용했고, 프런트엔드는 JavaScript, 시각화 라이브러리는 D3.js, HTML, CSS를 사용하여 만들어졌습니다. ((https://plot.ly/)


Plotly는 그래프가 (다른 시각화 라이브러리 대비) 아름답구요, 웹 상에 publish 하여 interactive visualization 용도로 사용하는데 매우 훌륭합니다. 


특히 Plotly Dash는 웹 기반 분석 애플리케이션 개발을 위한 오픈소스 파이썬 프레임워크인데요, JavaScript 를 안쓰고도 Python 코드 몇 백 줄로 Data Scientist가 디자이너 도움없이 매우 아름답고 완성도 높은 interactive analytics web application을 짧은 시간안에 만들 수 있어서 매우 매력적입니다. (for more information: https://dash.plot.ly/)


이번 포스팅에서는 웹에 publish 하는 것이 아니고, 로컬 컴퓨터에서 Jupyter Notebook에 offline으로 Plotly 라이브러리를 사용해서 시각화를 하는 방법을 소개하고자 합니다. 



  1. Plotly python package 설치(installation) 및 업그레이드(upgrade)


Plotly를 처음 사용하는 것이면 프롬프트 창에서 먼저 설치를 해야 합니다. 

 

$ pip install plotly




이미 Plotly를 설치해서 사용하고 있는 사용자라면, Plotly가 자주 버전 업그레이드를 하므로 아래처럼 Plotly를 업그레이트를 먼저 해주는 것을 추천합니다. 



$ pip install plotly --upgrade

 




  2. Plotly를 오프라인에서 사용하기 위한 라이브러리 import 및 환경 설정



# import plotly standard

import plotly.plotly as py

import plotly.graph_objs as go

import plotly.figure_factory as ff


# Cufflinks wrapper on plotly

import cufflinks as cf


# Display all cell outputs

from IPython.core.interactiveshell import InteractiveShell


# plotly + cufflinks in offline mode

from plotly.offline import iplot

cf.go_offline()


# set the global theme

cf.set_config_file(world_readable=True, theme='pearl', offline=True)

 




저의 로컴 컴퓨터에서 오프라인 Jupyter Notebook으로 Plotly의 interactive visualization 을 (1) 히스토그램(histogram), (2) 산점도행렬(scatterplot matrix) 의 두개 예를 들어보겠습니다. 


예제 데이터는 iris 데이터프레임입니다. seaborn 패키지에서 iris 데이터셋을 불러오겠습니다. 



import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

import seaborn as sns

 



# data loading

iris = sns.load_dataset('iris')

iris.shape

(150, 5) 




iris.head()

sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa




  (3) Plotly를 오프라인 Jupyter Notebook에서 사용한 히스토그램(histogram)


(3-1) 각 bin별 빈도(count, frequency)로 히스토그램 그리기


'petal_length' 변수에 대해서 iplot() 함수를 사용하여 20개의 bin으로 나누어서 빈도(count)를 기준으로 히스토그램을 그렸습니다.  아래는 화면 캡쳐한 이미지이다 보니 고정된 그래프인데요, Jupyter Notebook에서 마우스를 그래프 위에 가져다 대면 각 bin의 구간과 빈도가 화면에 interactive하게 나타납니다. 특정 구역을 마우스로 블럭을 설정하면 그 부분만 확대되어서 나타납니다(hover 기능). 



# Histogram with Frequency

iris['petal_length'].iplot(

    kind='hist', 

    bins=20, 

    xTitle='Petal Length(cm)', 

    linecolor='gray', 

    yTitle='Count', 

    title='Histogram of Petal Length')





(3-2) 각 bin별 구성비율로 히스토그램 그리기



# Histogram with Percentage

iris['petal_length'].iplot(

    kind='hist', 

    bins=20, 

    xTitle='Petal Length(cm)', 

    linecolor='gray', 

    histnorm='percent',

    yTitle='Percentage(%)', 

    title='Histogram of Petal Length in Percent')



 




  (4) Plotly를 오프라인 Jupyter Notebook에서 사용한 산점도 행렬(scatterplot matrix)


아래의 Plotly로 그린 산점도 행렬도 마우스를 가져다대면 interactive하게 해당 값이 화면에 나와서 바로 확인을 할 수 있습니다. 



fig = ff.create_scatterplotmatrix(

    iris[['petal_width', 'petal_length', 'sepal_width', 'sepal_length']],

    height=800,

    width=800, 

    diag='histogram') # scatter, histogram, box

iplot(fig)



 



Plotly로 그릴 수 있는 다양한 그래프 예제는 https://plot.ly/d3-js-for-python-and-pandas-charts/ 를 참고하시기 바랍니다. 


많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.



Posted by R Friend R_Friend

이번 포스팅에서는 두개 이상의 다변량 범주형 자료 시각화(visualization with multiple categorical data)의 하나로서 모자이크 그래프 (mosaic chart)를 그리는 방법을 소개하겠습니다. 




statsmodels 라이브러리의 statsmodels.graphics.mosaicplot 내 mosaic 클래스를 사용하면 매우 간단한 코드로 그릴 수 있습니다. 



import numpy as np

import pandas as pd


from statsmodels.graphics.mosaicplot import mosaic

import matplotlib.pyplot as plt

import seaborn as sns

plt.rcParams['figure.figsize'] = [12, 8]

 



예제로 사용할 데이터는 Titanic 침몰로 부터 생존/사망자 데이터셋입니다. 몇 년 전에 Kaggle에서 생존 vs. 사망 분류 모델 만들기 competition을 했었던 데이터입니다. 



# Getting Titanic dataset

url = "https://raw.github.com/mattdelhey/kaggle-titanic/master/Data/train.csv"

titanic = pd.read_csv(url)

titanic.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 11 columns):
survived    891 non-null int64
pclass      891 non-null int64
name        891 non-null object
sex         891 non-null object
age         714 non-null float64
sibsp       891 non-null int64
parch       891 non-null int64
ticket      891 non-null object
fare        891 non-null float64
cabin       204 non-null object
embarked    889 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 76.6+ KB

 



모자이크 그래프 시각화에 사용할 3개의 범주형 변수만 남겨놓았으며, 변수 이름과 코드값을 map() 함수를 사용하여 바꾸어보았습니다. 



titanic = titanic[['survived', 'pclass', 'sex']]


# make new variables of 'survived' and 'pclass' with the different class name

titanic["SURVIVE"] = titanic.survived.map({0: "DEAD", 1: "ALIVE"})

titanic["CLASS"] = titanic.pclass.map({1: "1ST", 2: "2ND", 3: "3RD"})

titanic["GENDER"] = titanic.sex.map({'male': 'MAN', 'female': "WOMAN"})


titanic.head()

survivedpclasssexSURVIVECLASSGENDER
003maleDEAD3RDMAN
111femaleALIVE1STWOMAN
213femaleALIVE3RDWOMAN
311femaleALIVE1STWOMAN
403maleDEAD3RDMAN

 




mosaic() 함수를 사용하여 생존여부('SURVIVE')와 티켓 등급('CLASS') 간의 관계를 알아볼 수 있는 모자이크 그래프를 그려보았습니다. 'CLASS' 변수의 코드값을 titanic.sort_values() 로 먼저 정렬을 한 후에 모자이크 그림을 그렸습니다. 1등석('1ST') > 3등석('3RD) > 2등석('2ND')의 순서로 생존율이 높게 나왔군요. 



from statsmodels.graphics.mosaicplot import mosaic

 

mosaic(titanic.sort_values('CLASS'), ['SURVIVE', 'CLASS'], 

      title='Mosaic Chart of Titanic Survivor')

plt.show()




이번에는 생존 여부('SURVIVE')와 성별('GENDER')와의 관계를 알아볼 수 있는 모자이크 그래프를 그려보았습니다. '여성('WOMEN')'의 생존자 비율이 높게 나왔습니다. 



mosaic(titanic, ['SURVIVE', 'GENDER'])

plt.title('Mosaic Chart of Titanic', fontsize=20)

plt.show()




생존 여부('SURVIVE'), 티켓 등급('CLASS'), 성별('GENDER') 3개 범주형 변수를 모두 한꺼번에 사용해서 모자이크 그림을 그릴 수도 있습니다. 



mosaic(titanic.sort_values('CLASS'), ['CLASS', 'SURVIVE', 'GENDER'])

plt.title('Mosaic Chart of Titanic', fontsize=20)

plt.show()

 





조금 더 가독성을 높이기 위해서 gap argument를 사용하여 변수 내 계급 간에 간극(gap)을 좀더 벌려서 모자이크 그림을 그릴 수 있습니다. 



mosaic(titanic.sort_values('CLASS'), ['CLASS', 'SURVIVE', 'GENDER'], 

      gap=0.02)

plt.title('Survivor of Titanic', fontsize=20)

plt.show()

 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ;-)



Posted by R Friend R_Friend

이번 포스팅에서는 시간의 흐름에 따른 관측값의 변화, 추세를 시각화하는데 유용한 선 그래프 (Line Graph)matplotlib, seaborn, pandas 라이브러리로 그리는 방법을 차례대로 소개하겠습니다. 


선 그래프를 그리려면 X좌표와 Y좌표별 값을 순서대로 선으로 이어주면 되는데요, X좌표, Y좌표, 값의 데이터 형태는 리스트, Series, 데이터프레임 등 여러가지가 가능합니다. 이번 포스팅에서는 이중에서도 (1) 옆으로 긴 데이터프레임(Wide-form DataFrame)과, (2) 아래로 긴 데이터프레임(Long-form DataFrame)을 사용하여 선 그래프 (Line Graph) 그리는 방법을 소개하겠습니다. 



[ 선 그래프를 그리는 두 가지 형태의 DataFrame: Wide-form, Long-form DataFrame ]




먼저 난수를 사용하여 4개의 연속형 변수를 가지는 시계열(time-series) 데이터셋을 (1) Wide-form DataFrame 과 (2) Long-form DataFrame을 만들어보겠습니다. 



  (Data form 1) Wide-form DataFrame



import numpy as np

import pandas as pd


import matplotlib.pyplot as plt

import seaborn as sns

plt.rcParams['figure.figsize'] = [12, 8]

 



np.random.seed(123) # for reproducibility

index = pd.date_range("1 1 2010", 

                      periods=100, 

                      freq="m", 

                      name="Date")


data = np.random.randn(100, 4).cumsum(axis=0)


wide_df = pd.DataFrame(data, index, ['a', 'b', 'c', 'd'])

wide_df.shape

(100, 4)

 

wide_df.head()

abcd
Date
2010-01-31-1.0856310.9973450.282978-1.506295
2010-02-28-1.6642312.648782-2.143701-1.935207
2010-03-31-0.3982951.782042-2.822587-2.029916
2010-04-301.0930951.143140-3.266569-2.464268
2010-05-313.2990253.329926-2.262515-2.078081





  (Data form 2) Long-form DataFrame



# stack to reshape from wide to long

long = wide_df.stack()

 

long_df = pd.DataFrame(long).reset_index()


long_df.head()

Datelevel_10
02010-01-31a-1.085631
12010-01-31b0.997345
22010-01-31c0.282978
32010-01-31d-1.506295
42010-02-28a-1.664231


# change column nane

long_df.columns = ['Date', 'Group', 'CumVal']

long_df.head()

DateGroupCumVal
02010-01-31a-1.085631
12010-01-31b0.997345
22010-01-31c0.282978
32010-01-31d-1.506295
42010-02-28a-1.664231


long_df.shape

(400, 3)


# adding a 'Size' column based on 'Group'

long_df['Size'] = np.where(long_df['Group'] == 'a', 1, 

                           np.where(long_df['Group'] == 'b', 2, 

                                    np.where(long_df['Group'] == 'c', 3, 4)))


long_df.head(n=12)

DateGroupCumValSize
02010-01-31a-1.0856311
12010-01-31b0.9973452
22010-01-31c0.2829783
32010-01-31d-1.5062954
42010-02-28a-1.6642311
52010-02-28b2.6487822
62010-02-28c-2.1437013
72010-02-28d-1.9352074
82010-03-31a-0.3982951
92010-03-31b1.7820422
102010-03-31c-2.8225873
112010-03-31d-2.0299164






  1. matplotlib으로 선 그래프 그리기 (Line Graph by matplotlib)


1-1. Wide-form DataFrame


matplotlib 으로 선 그래프를 그릴 때 점의 모양(marker)와 색깔을 4개 변수별로 다르게 설정해보았습니다. 



# Line Graph by matplotlib with wide-form DataFrame

plt.plot(wide_df.index, wide_df.a, marker='s', color='r')

plt.plot(wide_df.index, wide_df.b, marker='o', color='g')

plt.plot(wide_df.index, wide_df.c, marker='*', color='b')

plt.plot(wide_df.index, wide_df.d, marker='+', color='y')


plt.title('Line Graph w/ different markers and colors', fontsize=20) 

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')

plt.show()


 




아래는 선 모양(line style)과 선 두께(line width)을 4개 변수별로 다르게 설정해보았습니다. 



# Line Graph by matplotlib with different line style and line width

plt.plot(wide_df.index, wide_df.a, linestyle='--', linewidth=1) # 'dashed'

plt.plot(wide_df.index, wide_df.b, linestyle='-', linewidth=2) # solid

plt.plot(wide_df.index, wide_df.c, linestyle=':', linewidth=3) # dotted

plt.plot(wide_df.index, wide_df.d, linestyle='-.', linewidth=4) # dashdotted


plt.title('Line Graph w/ different linestyles and linewidths', fontsize=20) 

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')

plt.show()




1-2. Long-form DataFrame


Long-form DataFrame으로 선 그래프를 그릴 때는 for loop 문을 사용해서 변수 별로 subsetting 을 해서 차례대로 선 그래프를 겹쳐서 그려줍니다. (matplotlib이 for loop 문으로 복잡하다면 다음의 seaborn은 상대적으로 매우 깔끔함)



long_df.head(n=8)

DateGroupCumValSize
02010-01-31a-1.0856311
12010-01-31b0.9973452
22010-01-31c0.2829783
32010-01-31d-1.5062954
42010-02-28a-1.6642311
52010-02-28b2.6487822
62010-02-28c-2.1437013
72010-02-28d-1.9352074


# Line graph with long-form DataFrame

groups = ['a', 'b', 'c', 'd']

linewidths = [1, 2, 3, 4]


for group_name, size in zip(groups, linewidths):

    # subsetting

    long_df_sub = long_df[long_df['Group'] == group_name]


    # plotting

    plt.plot(long_df_sub.Date, long_df_sub.CumVal, linewidth=size)


plt.legend(['a', 'b', 'c', 'd'], fontsize=12, loc='best')

plt.show()





  2. seaborn으로 선 그래프 그리기 (Line Graph by seaborn)


2-1. Wide-form DataFrame


데이터셋이 Wide-form DataFrame 형태이면 sns.lineplot(data=df_name) 딱 한줄이면 디폴트 세팅 만으로도 매우 보기에 좋은 선 그래프가 그려집니다. 



# Line graph by seaborn

ax = sns.lineplot(data=wide_df)


plt.title('Line Graph w/ Wide-form DataFrame by seaborn', fontsize=20)

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')


plt.show()




2-2. Long-form DataFrame


seaborn 라이브러리의 묘미는 hue argument를 사용할 때입니다. ^^ hue='Group'변수별로 색깔을 다르게 하고, size='Size' 변수값에 따라 선 굵기(size)를 다르게 해보겠습니다. 



# Line graph with long-form DataFrame

long_df.head(n=8)

DateGroupCumValSize
02010-01-31a-1.0856311
12010-01-31b0.9973452
22010-01-31c0.2829783
32010-01-31d-1.5062954
42010-02-28a-1.6642311
52010-02-28b2.6487822
62010-02-28c-2.1437013
72010-02-28d-1.9352074


ax = sns.lineplot(x='Date', 

                  y='CumVal', 

                  hue='Group',

                  size='Size',

                  data=long_df)


plt.title('Line Graph of different size w/ Long-form df by seaborn', fontsize=20)

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')


plt.show()

 



style argument를 사용하여 선의 형태(line style)을 다르게 설정해보겠습니다. 참고로 style에 설정하는1, 2, 3, 4 숫자별로 선의 형태가 solid, dashed, dotted, dash-dotted 입니다. 



ax = sns.lineplot(x='Date', 

                  y='CumVal', 

                  #hue='Group',

                  style='Size',

                  data=long_df)


plt.title('Line Graph of different style w/ Long-form df by seaborn', fontsize=20)

plt.ylabel('Cummulative Num', fontsize=14)

plt.xlabel('Date', fontsize=14)

plt.legend(fontsize=12, loc='best')


plt.show()

 





  3. pandas로 선 그래프 그리기 (Line Graph by pandas)


3-1. Wide-form DataFrame


pandas 의 DataFrame에 대해서 df.plot.line() 혹은 df.plot(kind='line') 의 format으로 선 그래프를 그릴 수 있습니다. 



wide_df.head()

abcd
Date
2010-01-31-1.0856310.9973450.282978-1.506295
2010-02-28-1.6642312.648782-2.143701-1.935207
2010-03-31-0.3982951.782042-2.822587-2.029916
2010-04-301.0930951.143140-3.266569-2.464268
2010-05-313.2990253.329926-2.262515-2.078081


 # Line Graph by pandas

wide_df.plot.line()


plt.title('Line Graph with Wide-form df by pandas', fontsize=20)

plt.xlabel('Date', fontsize=14)

plt.ylabel('Cummulative Value', fontsize=14)

plt.legend(fontsize=12, loc='best')

plt.show()




# accessed by calling the accessor as a method with the ``kind`` argument

wide_df.plot(kind='line')

plt.show()




3-2. Long-form DataFrame


세로로 긴 형태의 DataFrame은 plt.subplots() 에 groupby() operator 와 함께 for loop 문을 사용해서 df.plot(ax=ax, kind='line') syntax 로 선 그래프를 그립니다. 좀 복잡하지요? 



long_df.head(n=8)

DateGroupCumValSize
02010-01-31a-1.0856311
12010-01-31b0.9973452
22010-01-31c0.2829783
32010-01-31d-1.5062954
42010-02-28a-1.6642311
52010-02-28b2.6487822
62010-02-28c-2.1437013
72010-02-28d-1.9352074


# Line plot w/ Long-form df by pandas

fig, ax = plt.subplots()


for key, grp in long_df.groupby('Group'):

    ax = grp.plot(ax=ax, kind='line', x='Date', y='CumVal', label=key)


plt.title('Line Graph with Long-form df by pandas', fontsize=20)

plt.xlabel('Date', fontsize=14)

plt.ylabel('Cummulative Value', fontsize=14)

plt.legend(fontsize=12, loc='best')

plt.show()



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^^


Posted by R Friend R_Friend

이번 포스팅에서는 산점도(scatter plot)의 마지막으로서, 여러개의 연속형 변수에 대해서 각 각 쌍을 이루어서 산점도를 그려서 한꺼번에 변수 간 관계를 일목요연하게 볼 수 있는 산점도 행렬 (scatterplot matrix)에 대해서 알아보겠습니다. 



(1) 산점도 (Scatter Plot)

(2) 그룹별 산점도 (Scatter Plot by Groups)

(3) 4개 변수로 산점도 크기 및 색깔 다르게 그리기 (Scatterplot with 4 variables)

(4) 산점도 행렬 (Scatter Plot Matrix)

 



예제로 사용할 데이터는 iris 데이터셋에 들어있는 4개의 연속형변수들인 'petal_length', 'petal_width', 'sepal_length', 'sepal_width' 입니다. 


matplotlib 으로 산점도 행렬을 그리려면 코드가 너무 길어지고 가독성도 떨어지므로 추천하지 않으며, seaborn 과 pandas, plotly 를 사용한 산점도 행렬만 소개하겠습니다. 



import numpy as np

import pandas as pd


import matplotlib.pyplot as plt

import seaborn as sns

 



# iris data loading

iris = sns.load_dataset('iris')

iris.shape

(150, 5)


iris.head()

sepal_lengthsepal_widthpetal_lengthpetal_widthspecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa





  (1) seaborn을 이용한 산점도 행렬 (scatterplot matrix by seaborn)


default 설정을 사용하여 4개의 연속형 변수만을 가지고 그린 산점도 행렬입니다. ('species' 범주형 변수는 알아서 무시해주니 참 편리합니다!)  코드도 간결하고 그래프도 깔끔하니 이뻐서 정말 마음에 듭니다! 

대각원소 자리에는 diag_kind='hist' 를 설정하여 각 변수별 히스토그램을 볼 수 있게 하였습니다. 



# scatterplot matrix with histogram only for continuous variables

sns.pairplot(iris, diag_kind='hist')

plt.show()


 




아래의 산점도 행렬에는 diag_kind='kde' 를 사용하여 각 변수별 커널밀도추정곡선을 볼 수 있게 하였으며, hue='species'를 사용하여 'species' 종(setosa, versicolor, virginica) 별로 색깔을 다르게 표시하여 추가적인 정보를 알 수 있도록 하였습니다. 색깔은 palette 에 'bright', 'pastel', 'deep', 'muted', 'colorblind', 'dark' 중에서 가독성이 좋고 선호하는 색상으로 선택하면 됩니다. 


아래 그래프를 이처럼 간결한 코드로 아름답게 그릴 수 있다니 seaborn 참 매력적입니다!



# Scatterplot matrix with different color by group and kde

sns.pairplot(iris, 

             diag_kind='kde',

             hue="species", 

             palette='bright') # pastel, bright, deep, muted, colorblind, dark

plt.show()






  (2) pandas를 이용한 산점도 행렬 (scatterplot matrix by pandas)


아래는 pandas.plotting 의 scatter_matrix() 함수를 사용하여 산점도 행렬을 그려본 것인데요, 코드가 간결하긴 하지만 위의 seaborn 대비 그래프가 그리 아름답지는 않고 좀 투박합니다. 



# scatterplot matrix by pandas scatter_matrix()

from pandas.plotting import scatter_matrix

scatter_matrix(iris, 

               alpha=0.5, 

               figsize=(8, 8), 

               diagonal='kde')

plt.show()




  (3) plotly를 이용한 산점도 행렬 (interactive scatterplot matrix by plotly)


plotly를 이용하면 분석가와 상호작용할 수 있는 역동적인 산점도 행렬 (interactive scatterplot matrix)을 만들 수 있습니다. API 대신에 오프라인 모드(offline mode)에서 사용할 수 있도록 아래에 제시한 패키지들을 pip로 설치하고, import 해주어야 합니다. 



# import plotly standard

import plotly.plotly as py

import plotly.graph_objs as go

import plotly.figure_factory as ff


# Cufflinks wrapper on plotly

import cufflinks as cf


# Display all cell outputs

from IPython.core.interactiveshell import InteractiveShell


# plotly + cufflinks in offline mode

from plotly.offline import iplot

cf.go_offline()


# set the global theme

cf.set_config_file(world_readable=True, theme='pearl', offline=True)

 




plotly.offline의 iplot을 사용하여 오프라인 모드에서 산점도 행렬을 그린 결과입니다. iag='histogram'으로 대각 행렬 위치에는 각 변수의 히스토그램을 그렸으며, 'scatter' (점 그림)와 'box' (박스 그림) 을 설정할 수도 있습니다. 


아래는 화면 캡펴한 이미지를 넣었는데요, jupyter notebook에서 보면 커서를 가져다데는 곳에 x, y 좌표 값이 실시간으로 화면에 INTERACTIVE하게 나타납니다. hover 기능도 있어서 커서로 블록을 설정하면 블록에 해당하는 부분만 다시 산점도가 그려지기도 하며, file로 바로 다운로드도 가능합니다. 



fig = ff.create_scatterplotmatrix(

    iris[['petal_width', 'petal_length', 'sepal_width', 'sepal_length']],

    height=800,

    width=800, 

    diag='histogram') # scatter, histogram, box


iplot(fig) # offline mode

 





아래의 산점도 행렬에서는 대각행렬 위치에 '박스 그림 (diag='box')'을 제시하였고, 산점도와 대각원소의 박스 그림을 index='species'를 사용하여 3개 종(setosa, versicolor, virginica) 별로 색깔을 다르게 구분해서 그려본 것입니다. 


아래 그림은 화면 캡쳐한 것이어서 interactive 하지 않은데요 (-_-;;;), jupyter notebook에서 실행해보면 커서를 위로 올려놓으면 데이터 값이 나오구요, 줌 인/아웃, hover, 다운로드 등 interactive 한 시각화가 가능합니다. 



# scatterplot matrix by plotly with box plot at diagonal & different color by index(GROUP)

fig = ff.create_scatterplotmatrix(

    iris,

    height=800,

    width=800, 

    diag='box', # scatter, histogram, box

    index='species')


iplot(fig)

 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^^


Posted by R Friend R_Friend