ETH官方钱包

前往
大廳
主題

AI跨領域數據科學 課程紀錄 d36~37 智慧醫療 (2-3) 醫療生醫大數據

傳說中的巴哈魔法師~ | 2022-05-04 22:23:04 | 巴幣 0 | 人氣 189

安裝imageio模組
pip install imageio

-
讀入圖像

使用imageio模組
imageio.imread 載入圖片
torch.from_numpy 轉為張量

import numpy as np
import torch
import imageio
img_arr = imageio.imread('./bobby.jpg') #載入一張圖片
img = torch.from_numpy(img_arr) #先將img_arr轉成PyTorch張量(以img表示)
img.shape

torch.Size([720, 1280, 3])

由於PyTorch格式要求,之後需要轉置成 [3, 720, 1280]

cf.
使用PIL (Pillow模組)
Image.open 載入圖片
transforms.ToTensor() "圖片"轉為張量

from PIL import Image
from torchvision import transforms
img_arr = Image.open('./bobby.jpg')
img = transforms.ToTensor()(img_arr)
img.shape

torch.Size([3, 720, 1280])

-
讀資料夾內檔案

os模組
import os

os.listdir(資料夾路徑) : 資料夾下所有檔案(含副檔名) 以list顯示 每個檔案一項
os.path.splitext(檔案名稱) : 將檔案名稱分為 檔名[0] 副檔名[1]

將image-cats資料夾中所有png檔案(全彩 256*256) 讀入最多100張到batch張量中

batch = torch.zeros(100, 3, 256, 256, dtype=torch.uint8) #創一個 100張 全彩 256*256 的張量

import os
filenames = [name for name in os.listdir('./image-cats/') if os.path.splitext(name)[1] == '.png']
for i, filename in enumerate(filenames): #依序載入每個png檔 (必須都是全彩256*256的)
    img_arr = imageio.imread('./image-cats/'+ filename) #filename格式是str
    img_t = torch.from_numpy(img_arr)
    img_t = img_t.permute(2, 0, 1) #調整張量中各軸的排列順序    
    batch[i] = img_t #將圖片存入batch張量中
    
batch.shape #輸出batch張量的shape

torch.Size([100, 3, 256, 256])

進行前處理 (顏色數值正規化)

batch = batch.float() #將batch張量內的像素值轉換成浮點數
batch /= 255.0 #將像素值同除以255
#因為CNN網路需要調整

n_channels = batch.shape[1] #取得色彩通道的數量(batch張量的shape中,第1軸維度)
for c in range(n_channels): #依次走訪每個色彩通道
    mean = torch.mean(batch[:, c]) #計算平均值
    std = torch.std(batch[:, c]) #計算標準差
    batch[:, c] = (batch[:, c] - mean) / std #正規化的公式
    
# 轉換後的平均值=0、標準差=1

-
讀入"特殊格式"圖片資料

使用imageio模組

imageio.volread(資料夾路徑,檔案格式) : 讀入指定格式圖片
volumetric-dicom/2-LUNG 3.0  B70f-04083 資料夾中的 99張dcm檔

vol_arr = imageio.volread("./volumetric-dicom/2-LUNG 3.0  B70f-04083", 'DICOM') #讀取檔案,存放在vol_arr

vol_arr.shape #輸出vol_arr的shape

(99, 512, 512)

進行前處理 (維度調整 加入通道軸與深度軸)
張量名稱 = torch.unsqueeze(張量名稱, 要在"第幾軸"的位置插入一軸) : 插入一軸 原本第那軸(含)之後後挪

vol = torch.from_numpy(vol_arr).float() #先把資料轉成浮點數張量
vol = torch.unsqueeze(vol, 1) #在第"1"軸的位置增加插入一個通道軸,維度為1
vol = torch.unsqueeze(vol, 1) #在第"1"軸的位置增加插入一個深度軸,維度為1

vol.shape
#增加維度

torch.Size([99, 1, 1, 512, 512])

-

使用csv模組 (搭配with開啟檔案)
with open(檔案路徑,"r") as 自訂名稱:
        CSV格式檔案名稱=csv.reader(自訂名稱, delimiter=分割條件)

import csv
with open("./tabular-wine/winequality-white.csv", 'r') as f:
    data = list(csv.reader(f, delimiter=";")) #轉成list

以二維list儲存

也可以使用open() (不用搭配with)
csv.reader(open(檔案路徑), delimiter=分割條件)

import csv
data = csv.reader(open("./tabular-wine/winequality-white.csv"), delimiter=";") #open()函數

col_list = next(data)
#next()函數 回傳迭代器的下一個項目

使用 next(可迭代資料) 函數
->產生第一行 的list 存在col_list
col_list:
['fixed acidity',
'volatile acidity',
'citric acid',
'residual sugar',
'chlorides',
'free sulfur dioxide',
'total sulfur dioxide',
'density',
'pH',
'sulphates',
'alcohol',
'quality']

使用pandas模組
pd.read_csv(檔案路徑,delimiter=分割條件)
可以加入skiprows=1 跳過首行不讀 只讀數值資料 (之後要轉張量 張量只能放數值)

import pandas as pd
df=pd.read_csv("./tabular-wine/winequality-white.csv",delimiter=";") #儲存成DataFrame

以DataFrame儲存 記錄index、columns名稱

使用numpy模組
np.loadtxt(檔案路徑, dtype=np.float32,delimiter=分割條件, skiprows=1)
這邊加入skiprows=1 跳過首行不讀 只讀數值資料 (之後要轉張量 張量只能放數值)

import numpy as np
wineq_numpy = np.loadtxt("./tabular-wine/winequality-white.csv", dtype=np.float32, delimiter=";", skiprows=1) #儲存成ndarray

以ndarray儲存 skiprows=1跳過第一行 只記錄數值

進行前處理 (轉為張量、quality欄位與其他欄位拆開)

剛剛使用pandas套件DataFrame儲存的話 可以使用pop (結果torch.from_numpy連pandas也可以轉@@)
DataFrame名稱.values 取數值 (不取index 、 columns)

y=torch.from_numpy(df.pop("quality").values) #最後一行(品質分數)的資料
x=torch.from_numpy(df.values) #除了最後一行(品質分數)之外的所有資料

y是quality欄位 (作為輸出)
x是其他欄位 (作為輸入)

使用numpy套件ndarray儲存的話

target = wineq[:, -1] #選擇最後一行(品質分數)的資料
data = torch.from_numpy(wineq_numpy)[:, :-1] #選擇除了最後一行(品質分數)之外的所有資料

target是quality欄位 (作為輸出)
data是其他欄位 (作為輸入)

one-hot 編碼
使用 scatter_ 自動回傳本身
需要插入數據的張量名稱.scatter_(one-hot編碼在"插入數據的張量名稱"的哪個維度,要改的張量名稱,要填入的東西)
如果是 scatter 則不回傳本身
需要插入數據的張量名稱 = 需要插入數據的張量名稱._scatter(one-hot編碼在"插入數據的張量名稱"的哪個維度,要改的張量名稱,要填入的東西)

target是quality欄位 數值為0~9 進行one-hot編碼
scatter要求資料格式torch.int64

target=target.to(torch.int64)

target.shape : [4898] 一維 4898項
故先建立target_onehot 張量 shape為[4898,10] 值均為0的張量,用來存放編碼結果

target_onehot = torch.zeros(target.shape[0], 10) #建立shape為[4898,10]、值均為0的張量,用來存放編碼結果

one-hot編碼

target_onehot.scatter_(1, target.unsqueeze(1), 1.0) #依target的內容進行編碼
#放在第1維(第0維是4898項), target增一維作為要改的張量, 填入1.0

target_onehot 第1000到1019項 :
(tensor([[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
         [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
         [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.]])

get_dummies 進行One Hot Encode
gender欄位直接分成兩行

data = pd.get_dummies(data)


tf.one_hot
label = tf.one_hot(label, NUM_CLASSES)

計算平均值
torch.mean(張量名稱, dim=0)
# dim等於axis 互通

計算標準差
torch.var(data, dim=0)

計算平方根
torch.sqrt(張量名稱)

數據標準化

data_mean = torch.mean(data, dim=0) #計算平均值 #dim=axis
data_var = torch.var(data, dim=0) #計算標準差
data_normalized = (data - data_mean) / torch.sqrt(data_var) #用Python實現標準化的公式

-
轉置


張量名稱 = 張量名稱.permute(4,2,3,0,1) #裡面填入自訂軸順序

cf.
transpose
指定兩軸互換

align_as

.t() 二維轉置

.T 任意維度轉置 順序顛倒

-
使用Bool-Tensor找值

bad_data = data[target <= 3] #利用索引篩選出符合目標的項目
bad_data

Bool-Series找值

-
比較

torch.lt #前者的資料<後者 True 反之 False
torch.lt(張量A,張量B) #可以挑出A中,值小於B的項目索引 回傳Bool-Tensor


-
張量名稱.dtype : 看資料型態

張量名稱[裡面可以放條件].sum(裡面可以放條件).item() : 可以看符合條件的項目數量的值加總

(裡面可以放條件).sum().item()
torch.sum(裡面可以放條件).sum().item() : 可以看符合條件的項目數量



np.loadtxt(檔案路徑,
              dtype=資料格式,
              comments=評論開始的字元或字元列表,
              delimiter=分割條件,
              converters=字典將列號對映到一個函式,該函式將把列的字串解析成所需的值,
              usecols=要讀取的列索引,
              unpack=是否對返回的陣列進行轉置,
              ndmin=返回陣列的最小維數,
              encoding=編碼方式,
              skiprows=跳過前幾行,
              max_rows=讀取 skiprows 行後的最大行數)

np.genfromtxt(檔案路徑,
              dtype=資料格式,
              comments=註釋標示符號,自動忽略註釋標是符號後面的字串
              delimiter=分割條件,
              converters=字典或lambda函數,將一種數據格式化成另一種數據格式,
              usecols=要讀取的列索引,
              unpack=是否對返回的陣列進行轉置,
              ndmin=返回陣列的最小維數,
              missing_values=視為遺失的值
              filling_values=替代遺失的值
              encoding=編碼方式,
              skip_header=跳過前幾行,
              skip_footer=跳過後幾行)

bikes_numpy = np.loadtxt("./bike-sharing-dataset/hour-fixed.csv",  #資料集所在路徑
                         dtype=np.float32,
                         delimiter=",",
                         skiprows=1,
                         converters={1: lambda x: float(x[8:10])})

converters={1: lambda x: float(x[8:10])}
1代表 處理第一直行
把其內容當作字串輸入 取字串中的第8到9個字元集合起來轉浮點數當作輸出

hour-fixed.csv檔案中 第1行是"dteday"資料
2012/11/24
2011/1/1
x[0:4] -> 第0~3個字元 2012 2011
第4個字元 /
x[5:7] -> 第5或第5~6個字元 1~12
第6或7個字元 /
x[8:10] -> 第7或第8~9個字元 1~31

= = 這超奇怪的 關於 / 他怎麼認知我搞不懂

另外
他是用字串作為讀入
關於這x
x[填第幾個]x[填區段] 有差別
np.loadtxt("./test.csv", converters={0: lambda x: float(x[4:5])})

這邊出來是第0直行每個字串中第4個字元轉浮點數

np.loadtxt("./test.csv", converters={0: lambda x: float(x[4])})

這邊出來是第0直行每個字串中第4個字元的ASCII碼轉浮點數

所以如果不想使用區段就必須再轉回去

np.loadtxt("./test.csv", converters={0: lambda x: float(chr(x[4]))})

-
view
類似轉置 類似reshape
但原理是:
將一個連續的張量攤平(1維)再重組成要的格式
所以需要填入的是連續的張量,輸出的也是連續的張量

裡面數字可以填-1 自動計算對應數值

a=torch.randn(4,5,6)
a.T.contiguous().view(5,8,-1).is_contiguous()

a張量 4*5*6
.T -> 轉置 變成不連續
.contiguous() -> 強制轉為連續張量
.view(5,8,-1) -> 變成連續張量 5*8*3 (3自動計算)
.is_contiguous() -> 是否是連續張量
True

-
單字進行one-hot 編碼

讀檔

with open('./1342-0.txt', encoding='utf-8-sig') as f:
    text = f.read()

拆字

words_in_book = [word.strip('.,;:"!?”“_-[]#*') for word in text.lower().split()]

建立字典

words_in_book_dict = {word: i for (i, word) in enumerate(sorted(set(words_in_book)))}
#key為單字,value為其編碼(就是該單字在單字串列中的索引)

使用字典 對檔案單字進行one-hot

words_onehot = torch.zeros(len(words_in_book), len(words_in_book_dict))
#創建一個張量,用來儲存編碼後的單字向量

for i, word in enumerate(words_in_book):
    words_index = words_in_book_dict[word]
    words_onehot[i][words_index] = 1

words_onehot.shape
torch.Size([124592, 7256])
總共有124592個單字、字典紀載7256個單字

words_onehot
tensor([[0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        ...,
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.]])

words_in_book_dict['impossible']
3390
impossible單字的編號是3390

list(word2index_dict.keys())[list(word2index_dict.values()).index(3390)]
'impossible'
編號3390的單字是impossible

創作回應

更多創作