學(xué)習(xí)寫(xiě)python包——data_models.py

scDataset 類(lèi)

from collections import Counter
from typing import Optional

import anndata
import numpy as np
import pandas as pd
import pytorch_lightning as pl
import scanpy
import torch
from torch.utils.data import Dataset, DataLoader, WeightedRandomSampler

class scDataset(Dataset):
    """A class that represent a single cell dataset."""

    def __init__(self, X, Y, study=None):
        self.X = X
        self.Y = Y
        self.study = study
        self.classes = set(self.Y)

    def __len__(self):
        return len(self.Y)

    def __getitem__(self, idx):
        # data, label, study
        return self.X[idx].A, self.Y[idx], self.study[idx]

這段代碼定義了 scDataset 類(lèi),它是一個(gè)用于表示單細(xì)胞數(shù)據(jù)集的 Python 類(lèi)悴品。這個(gè)類(lèi)繼承自 torch.utils.data.Dataset苔严,使其兼容于 PyTorch 的數(shù)據(jù)加載和處理機(jī)制。下面我將詳細(xì)解釋這個(gè)類(lèi)及其方法的功能:

導(dǎo)入的模塊
collections.Counter: 用于計(jì)數(shù)不同元素的出現(xiàn)次數(shù)欠窒。
typing.Optional: 用于類(lèi)型注解岖妄,表示參數(shù)可以為 None寂祥。
anndata: 用于處理單細(xì)胞數(shù)據(jù)的庫(kù)。
pytorch_lightning: 簡(jiǎn)化 PyTorch 模型訓(xùn)練的庫(kù)福扬。
scanpy: 用于單細(xì)胞數(shù)據(jù)分析的庫(kù)铛碑。

構(gòu)造函數(shù) init(self, X, Y, study=None)
參數(shù):

X: 數(shù)據(jù)矩陣虽界,通常是一個(gè)稀疏矩陣莉御,包含細(xì)胞的基因表達(dá)數(shù)據(jù)。
Y: 標(biāo)簽數(shù)組牍颈,包含與 X 中每個(gè)樣本相對(duì)應(yīng)的標(biāo)簽(例如晴圾,細(xì)胞類(lèi)型)死姚。
study: 可選參數(shù)勤篮,包含與 X 中每個(gè)樣本相對(duì)應(yīng)的研究或?qū)嶒?yàn)信息。
屬性初始化:

self.X: 存儲(chǔ)傳入的數(shù)據(jù)矩陣 X账劲。
self.Y: 存儲(chǔ)傳入的標(biāo)簽 Y瀑焦。
self.study: 存儲(chǔ)傳入的研究信息 study。
self.classes: 從 Y 中提取的唯一標(biāo)簽集合铺董,表示數(shù)據(jù)中包含的不同類(lèi)別精续。
len(self) 方法
返回?cái)?shù)據(jù)集中樣本的總數(shù)粹懒。這是通過(guò)計(jì)算 Y(標(biāo)簽數(shù)組)的長(zhǎng)度來(lái)實(shí)現(xiàn)的。
getitem(self, idx) 方法
參數(shù): idx - 請(qǐng)求的樣本索引确垫。
返回: 三元組 (data, label, study)森爽,其中:
data: 索引 idx 處的樣本數(shù)據(jù)(從 X 中提认怠)。.A 用于將稀疏矩陣轉(zhuǎn)換為常規(guī)數(shù)組付呕。
label: 索引 idx 處的樣本標(biāo)簽(從 Y 中提然罩啊)佩厚。
study: 索引 idx 處的樣本對(duì)應(yīng)的研究信息(從 study 中提取)潮瓶。

DataLoader

在 PyTorch Lightning 框架中毯辅,MetricLearningDataModule 類(lèi)繼承自 pl.LightningDataModule煞额。

DataLoader(
            self.train_dataset,
            batch_size=self.batch_size,
            num_workers=self.num_workers,
            pin_memory=True,
            drop_last=True,
            sampler=self.get_sampler_weights(self.train_dataset),
            collate_fn=self.collate)

DataLoader 是一個(gè)極其重要的工具,用于批量加載數(shù)據(jù)并為訓(xùn)練提供必要的輸入胀莹。為了使數(shù)據(jù)能夠被 DataLoader 正確讀取和處理,需要遵循特定的格式和協(xié)議涩僻。這就是為什么 scDataset 類(lèi)按照特定方式實(shí)現(xiàn)的原因逆日。
如何 scDataset 被 DataLoader 讀取:

  1. 繼承自 Dataset:

scDataset 繼承自 PyTorch 的 Dataset 類(lèi)萄凤,這意味著它需要實(shí)現(xiàn)兩個(gè)方法:lengetitem靡努。
len 返回?cái)?shù)據(jù)集中的樣本數(shù)。
getitem 根據(jù)給定的索引返回相應(yīng)的樣本兽泄。

  1. 數(shù)據(jù)格式:

getitem 返回一個(gè)包含數(shù)據(jù)病梢、標(biāo)簽和研究信息的元組梁肿。這是標(biāo)準(zhǔn)的 PyTorch 數(shù)據(jù)格式,允許 DataLoader 以一致的方式處理不同類(lèi)型的數(shù)據(jù)集钮热。

get_sampler_weights

其中隧期, get_sampler_weights(self, dataset)
這個(gè)函數(shù)用于根據(jù)數(shù)據(jù)集生成加權(quán)隨機(jī)采樣器赘娄。加權(quán)隨機(jī)采樣器在數(shù)據(jù)不平衡的情況下非常有用,它可以確保在訓(xùn)練過(guò)程中各類(lèi)別被均等地表示鸵闪。

   def get_sampler_weights(self, dataset: scDataset) -> WeightedRandomSampler:
        """Get weighted random sampler.
        WeightedRandomSampler
            A WeightedRandomSampler object.
        """
        if dataset.study is None:
            class_sample_count = Counter(dataset.Y)
            sample_weights = torch.Tensor(
                [1.0 / class_sample_count[t] for t in dataset.Y]
            )
        else:
            class_sample_count = Counter(dataset.Y)
            study_sample_count = Counter(dataset.study)
            sample_weights = torch.Tensor(
                [
                    1.0
                    / class_sample_count[dataset.Y[i]]
                    / np.log(study_sample_count[dataset.study[i]])
                    for i in range(len(dataset.Y))
                ]
            )
        return WeightedRandomSampler(sample_weights, len(sample_weights))

實(shí)現(xiàn)邏輯
參數(shù):dataset 是一個(gè) scDataset 類(lèi)的實(shí)例蚌讼,包含數(shù)據(jù)集的特征个榕、標(biāo)簽和其他信息。

處理:

如果 dataset 沒(méi)有提供 study 信息凰萨,則根據(jù)類(lèi)別標(biāo)簽 Y 計(jì)算每個(gè)類(lèi)別的樣本計(jì)數(shù)胖眷。然后霹崎,為每個(gè)樣本計(jì)算權(quán)重,權(quán)重為類(lèi)別的倒數(shù)境析。
如果提供了 study 信息劳淆,則同時(shí)考慮類(lèi)別和研究的影響默赂。在這種情況下,樣本的權(quán)重是類(lèi)別和研究的頻率的對(duì)數(shù)的倒數(shù)谒臼。
返回:返回一個(gè) WeightedRandomSampler 對(duì)象耀里,用于在數(shù)據(jù)加載過(guò)程中按照計(jì)算的權(quán)重隨機(jī)選擇樣本冯挎。

collate

def collate(self, batch):
        """Collate tensors.

        Parameters
        ----------
        batch:
            Batch to collate.

        Returns
        -------
        tuple
            A Tuple[torch.Tensor, torch.Tensor, list] containing information
            on the collated tensors.
        """
        profiles, labels, studies = tuple(
            map(list, zip(*batch))
        )  # tuple([list(t) for t in zip(*batch)])
        return (
            torch.squeeze(torch.Tensor(np.vstack(profiles))),
            torch.Tensor(labels),
            studies)

DataLoader 通過(guò) collate_fn 參數(shù)接收一個(gè)函數(shù)房官,該函數(shù)定義了如何將多個(gè)樣本組合成一個(gè)批次。這在處理不規(guī)則大小或不同類(lèi)型的數(shù)據(jù)時(shí)尤其重要孵奶。

collate 函數(shù)的工作流程如下:

輸入:batch蜡峰,一個(gè)包含多個(gè)從 scDataset.getitem 返回的元組的列表。
處理:
使用 zip(*batch) 將批次中的元素分解為單獨(dú)的列表(profiles, labels, studies)载绿。
將每個(gè)列表轉(zhuǎn)換為適當(dāng)?shù)?PyTorch 張量或保持為列表(如研究信息)。
對(duì)于數(shù)據(jù) profiles怀浆,使用 np.vstack 將它們垂直堆疊成一個(gè) NumPy 數(shù)組执赡,然后轉(zhuǎn)換為一個(gè) PyTorch 張量函筋。
返回:一個(gè)包含處理后的數(shù)據(jù)張量、標(biāo)簽張量和研究信息列表的元組

為什么這里需要一個(gè)collate_fn灌诅?

在 PyTorch 中含末,collate_fn 用于在數(shù)據(jù)加載過(guò)程中將多個(gè)樣本組合成一個(gè)批次佣盒。通常,如果你的數(shù)據(jù)集返回的每個(gè)樣本是一個(gè)簡(jiǎn)單的張量(比如圖片或標(biāo)簽)盯仪,你不需要提供一個(gè)自定義的 collate_fn蜜葱,因?yàn)?PyTorch 的默認(rèn) collate_fn 已經(jīng)可以處理這種情況。

然而爸黄,如果你的數(shù)據(jù)集返回的是復(fù)雜的數(shù)據(jù)結(jié)構(gòu)或需要特殊處理(比如不同的數(shù)據(jù)類(lèi)型組合炕贵、不規(guī)則的張量形狀等)野崇,那么你可能需要提供一個(gè)自定義的 collate_fn 來(lái)正確地處理這些數(shù)據(jù)。

為什么 scDataset 類(lèi)需要 collate_fn鳖轰?
scDataset 類(lèi)返回三種不同類(lèi)型的數(shù)據(jù):self.X(數(shù)據(jù)矩陣),self.Y(標(biāo)簽),和 self.study(研究)狈惫。這些數(shù)據(jù)可能需要特殊處理才能合并為一個(gè)批次,尤其是當(dāng)它們包含不同類(lèi)型的數(shù)據(jù)時(shí)忆肾。例如:

數(shù)據(jù)轉(zhuǎn)換:self.X 可能是一個(gè)稀疏矩陣客冈,需要轉(zhuǎn)換為密集張量稳强。
數(shù)據(jù)維度對(duì)齊:如果 self.X 中的樣本有不同的形狀,可能需要進(jìn)行填充或裁剪以確保它們可以合并渠缕。
額外信息合并:self.Y 和 self.study 可能需要特殊處理才能與 self.X 正確對(duì)應(yīng)褒繁。
什么時(shí)候不需要寫(xiě) collate_fn棒坏?
如果你的數(shù)據(jù)集返回的每個(gè)樣本已經(jīng)是一個(gè)規(guī)則的張量,且不需要任何特殊的預(yù)處理或后處理徒探,那么就不需要提供自定義的 collate_fn喂窟。在這種情況下,PyTorch 的默認(rèn) collate_fn 足以應(yīng)對(duì)大多數(shù)情況偷溺,它會(huì)自動(dòng)將多個(gè)樣本堆疊成一個(gè)批次挫掏。例如秩命,如果你的數(shù)據(jù)集只返回一組圖片和對(duì)應(yīng)的標(biāo)簽褒傅,而且所有圖片都有相同的形狀殿托,那么默認(rèn)的 collate_fn 就足夠了剧蚣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鸠按,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子馒吴,更是在濱河造成了極大的恐慌瑟曲,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莹捡,死亡現(xiàn)場(chǎng)離奇詭異扣甲,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)启泣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)寥茫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)矾麻,“玉大人,你說(shuō)我怎么就攤上這事弄喘∧⒅荆” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵澎媒,是天一觀的道長(zhǎng)波桩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)储玫,這世上最難降的妖魔是什么匀油? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任敌蚜,我火速辦了婚禮窝爪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纷跛。我一直安慰自己,他們只是感情好贫奠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布唤崭。 她就那樣靜靜地躺著谢肾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芦疏。 梳的紋絲不亂的頭發(fā)上酸茴,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天弊决,我揣著相機(jī)與錄音,去河邊找鬼与倡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛纺座,可吹牛的內(nèi)容都是我干的净响。 我是一名探鬼主播喳瓣,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼配乓!你這毒婦竟也來(lái)了犹芹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤腰埂,失蹤者是張志新(化名)和其女友劉穎蜈膨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體驴一,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛔趴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年孝情,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洒嗤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡羔挡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出利术,到底是詐尸還是另有隱情低矮,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布轮蜕,位于F島的核電站跃洛,受9級(jí)特大地震影響终议,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜韩玩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一陆馁、第九天 我趴在偏房一處隱蔽的房頂上張望叮贩。 院中可真熱鬧佛析,春花似錦、人聲如沸捺萌。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)态坦。三九已至伞梯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谜诫,已是汗流浹背漾峡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掰邢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓掰伸,卻偏偏與公主長(zhǎng)得像怀估,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歧蕉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容