close
close

first Drop

Com TW NOw News 2024

Nette DataFrames maar geen Tibbles
news

Nette DataFrames maar geen Tibbles

Een tijdje geleden (2019 lijkt nu alweer zo lang geleden) begon ik te werken aan iets dat ik interessant vond, maar dat nooit echt aansloeg. Het heeft weer potentie, dus het is hoog tijd dat ik opschrijf wat het doet en waarom ik denk dat het een nuttig idee is. Ik ga het hebben over het gebruik van het {dplyr}-pakket op wat data met rijen en kolommen, maar we hebben het niet over data.frames of
tibbleS…

Oké, ik moet er waarschijnlijk eerst even wat over vertellen.

Ik grijp deze kans ook aan om mijn eigen begrip van al deze stukken te versterken. Ik vind dat de beste manier om iets te leren is door het te onderwijzen.

data.frame

Een van de basisbouwstenen van data in R is de data.frame – technisch gezien een lijst met vectoren (vectoren moeten hetzelfde ‘type’ hebben, maar lijsten hebben deze beperking niet) waarbij de vectoren allemaal dezelfde lengte hebben. Een voorbeeld ziet er zo uit

d 

If we unpack that a bit, it is just a list of vectors

unclass(d)
## $x
## (1) 2 3 4 5
## 
## $y
## (1) "B" "C" "D" "E"
## 
## $z
## (1) 4+2i 5+2i 6+2i 7+2i
## 
## attr(,"row.names")
## (1) 1 2 3 4

en daar zien we nog een kenmerk; ze hebben een attribuut row.namesStandaard zijn dit gewoon getallen (gecodeerd als strings) die we kunnen bereiken met de rownames()
functie

rownames(d)
## (1) "1" "2" "3" "4"

Als je handleidingen over het gebruik van R hebt gelezen, heb je waarschijnlijk de mtcars dataset waarin deze rijnamen prominent voorkomen - hier zijn de eerste 4 rijen en kolommen

mtcars(1:4, 1:4)
##                 mpg cyl disp  hp
## Mazda RX4      21.0   6  160 110
## Mazda RX4 Wag  21.0   6  160 110
## Datsun 710     22.8   4  108  93
## Hornet 4 Drive 21.4   6  258 110

We kunnen die rijnamen extraheren

rownames(mtcars(1:4, 1:4))
## (1) "Mazda RX4"      "Mazda RX4 Wag"  "Datsun 710"     "Hornet 4 Drive"

Deze "rijnaam"-gegevens bevinden zich als het ware aan de zijkant van het gegevensobject, maar ja, ze zou kunnen leven “in” de data net zo goed als hun eigen vector. Dat is de aanpak die de tidyverse hanteert met tibbles. Er is echter nog een ander voordeel dat vaak over het hoofd wordt gezien.

In de bovenstaande voorbeelden heb ik enkele rijen van de mtcars data.frame met indices, maar de ( Deze methode werkt net zo goed met rij-ID's (strings)…

mercs 

You’re probably more familiar with this when subsetting columns, in which case you’re using the column names in exactly the same way

metrics 

As we’ll see, this becomes very convenient when we have meaningful identifiers in both dimensions.

{tibble}

A tibble is bijna precies zoals een data.frame behalve dat de printmethode het iets anders laat zien

tbl    
## 1  21       6   160   110
## 2  21       6   160   110
## 3  22.8     4   108    93
## 4  21.4     6   258   110

en de rijnamen zijn weg. Dat is met opzet, en wordt behoorlijk streng afgedwongen – als ik ze weer probeer toe te voegen, klaagt {tibble} en weigert

rownames(tbl)    
## 1  21       6   160   110
## 2  21       6   160   110
## 3  22.8     4   108    93
## 4  21.4     6   258   110

Maar de wereld draait door.

Als je hebben rijnamen die u echt wilt behouden, {tibble} heeft een manier om ze in hun eigen kolom te krijgen, zodat ze in een tibble

tbl_rows  
  tibble::rownames_to_column() |> 
  tibble::as_tibble()
tbl_rows
## # A tibble: 5 × 6
##   rowname      mpg   cyl  disp    hp  drat
##             
## 1 Valiant     18.1     6  225    105  2.76
## 2 Duster 360  14.3     8  360    245  3.21
## 3 Merc 240D   24.4     4  147.    62  3.69
## 4 Merc 230    22.8     4  141.    95  3.92
## 5 Merc 280    19.2     6  168.   123  3.92

Om het eerder beschreven benoemde subsetgedrag te verkrijgen, moeten we de
"rowname" kolom in de uitvoer en voer er wat filtering op uit om de rijen te krijgen die we willen

tbl_rows(tbl_rows$rowname %in% mercs, c("rowname", metrics))
## # A tibble: 3 × 4
##   rowname     mpg    hp  drat
##          
## 1 Merc 240D  24.4    62  3.69
## 2 Merc 230   22.8    95  3.92
## 3 Merc 280   19.2   123  3.92

Er is natuurlijk een betere manier om een ​​subset te maken tibble

{dplyr}

Wat betreft de interactie met deze objecten is {dplyr} geweldig – het doet denken aan SQL-syntaxis (SELECT, GROUP BY… kijk, het is niet 1:1, maar het lijkt er wel op) en zorgt voor een heel schone pijplijn voor gegevensverwerking – het werd al vroeg ingezet met ondersteuning voor de {magrittr}-pijplijn en het aanmoedigen van een ‘gegevens als eerste argument’-constructie, wat betekende dat het pijplijnen van de ene functie naar de andere soepel verliep.

Er is niet veel in {dplyr} dat je niet zou kunnen doen met een stel basisfuncties als je dat zou willen – en sommige mensen zijn zelfs zo ver gegaan om dat te bewijzen met niet-dplyr-pakketten met bijpassende functies maar basisinterne functies, waardoor de mogelijkheid van {dplyr} om verbinding te maken met een database met exact dezelfde code die je op een lokale server zou gebruiken, verloren gaat. tibble ({dbplyr} vertaalt de R-aanroepen achter de schermen naar de native SQL-syntaxis) voor meer debugbare code, bijvoorbeeld {poorman}.

{dplyr}-functies retourneren meestal dezelfde klasse als de invoer; als u mutate A
data.frame je krijgt een data.frame (wat niet altijd het geval was, maar nu minder verrassend is)

mtcars(1:5, 1:6) |> 
  dplyr::mutate(pwr = hp / wt)
##                    mpg cyl disp  hp drat    wt      pwr
## Mazda RX4         21.0   6  160 110 3.90 2.620 41.98473
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 38.26087
## Datsun 710        22.8   4  108  93 3.85 2.320 40.08621
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 34.21462
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 50.87209

Een kenmerk dat tibble voegt toe bovenop data.frame is het concept van “groepen”. Om deze reden, als u een groepering uitvoert op een data.frame je krijgt een tibble
omdat dat de enige ondersteunde optie is

# slice(1) on a data.frame returns 1 row of a data.frame
mtcars |> 
  dplyr::slice(1)
##           mpg cyl disp  hp drat   wt  qsec vs am gear carb
## Mazda RX4  21   6  160 110  3.9 2.62 16.46  0  1    4    4
# slice(1) on a grouped tibble returns 1 row _per group_ 
mtcars |> 
  dplyr::group_by(gear, am) |> 
  dplyr::slice(1)
## # A tibble: 4 × 11
## # Groups:   gear, am (4)
##     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
##             
## 1  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
## 2  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
## 3  21       6  160    110  3.9   2.62  16.5     0     1     4     4
## 4  26       4  120.    91  4.43  2.14  16.7     0     1     5     2

{tibble} slaat deze informatie op in een speciaal "groups" kenmerk, en zorgt ervoor dat {dplyr} functies hiervan op de hoogte zijn. Het drukt deze informatie ook af boven het object (plus het aantal resulterende ‘groepen’).

Is er iets wat het niet kan?

Een geheel nieuwe wereld

Dat werd uiteindelijk een hoop achtergrond, blij om te zien dat je er nog bent. Dat is {dplyr} die een data.frame of een tibble om veel nuttige bewerkingen op data uit te voeren. Als u, net als ik voordat u de wereld van de computationele biologie betrad, dacht dat dit alles was, dan is het volgende deel een beetje een eyeopener.

Net als in een videogame waar de kaart ineens twee keer zo groot blijkt te zijn als je dacht, is er een hele wereld aan R-pakketten buiten CRAN, voornamelijk gericht op computationele biologie/bioinformatica, bekend als Bioconductor. Dit wordt goed ondersteund door het R-project zelf, maar je zou je hele leven kunnen besteden aan het schrijven van R-analyses en het nooit gebruiken als je niet aan bioinfo-dingen werkt.

Ik denk niet dat ik iets van Bioconductor had gebruikt voordat ik bij een groot biotechbedrijf ging werken – toevallig bij het bedrijf waar Robert Gentleman zelf senior director was in bioinformatica en computationele biologie tot een paar jaar voordat ik erbij kwam. In de jaren erna raakte ik echter erg bekend met de pakketten die in die ruimte werden aangeboden.

In de wereld van het sequencen van data is de nederige data.frame heeft gewoon niet de juiste hoeveelheid structuur – rechthoekige data is geweldig, maar ongeacht welke kant je op draait (breed of lang), je zult moeite hebben om alle verschillende kwaliteiten en hoeveelheden die aan een sample zijn gekoppeld weer te geven; bijvoorbeeld het weergeven van het expressieniveau van een gen voor samples die behoren tot een subject, waarbij zowel het subject als het sample metadata hebben, net als het experiment zelf, net als de genen. Houd er rekening mee dat dit duizend samples en vele tienduizenden genen kan omvatten, een platte tabel is gewoon niet voldoende.

Een betere optie is om een ​​andere structuur te creëren, een die de verschillende componenten (sample metadata, gene metadata) uitgelijnd en bij elkaar houdt, maar niet in dezelfde tabel. Verschillende hiervan zijn in de loop van de tijd geëvolueerd, maar een huidige favoriet van het veld is de SummarizedExperiment structuur. Dit organiseert de componenten op een manier dat ze kunnen worden opgeslagen en ondervraagd zonder dat er een dozijn filters hoeven te worden uitgevoerd om bij de hoek van de gegevens te komen waarin u geïnteresseerd bent.

Als we dit zien als een database, hebben we een tabel voor de werkelijke metingen, een andere voor de voorbeeldmetadata en een andere voor de metadata over de dingen die worden waargenomen (bijvoorbeeld genen). Het probleem is dat we sleutels moeten definiëren die de verschillende tabellen met elkaar verbinden. Als onze metingen een gigantische matrix van waarden waren, bijvoorbeeld

expression_data 

how would we know that the second column is for sample_Y and the third row is for gene_DEF? The matrix itself is numeric, so we can’t just add a new row/column to store the sample/gene information, which is character.

No points for guessing that the intro above was for a reason - those attributes are now really useful.

library(charcuterie)
rownames(expression_data) 

Much clearer! Even better, now we have a way to link up the metadata in either dimension.

For the samples, we can create a data.frame with the relevant metadata for each sample, and label each sample row with the relevant ID

sample_metadata 

Now we can imagine taking this metadata and sort of turning it sideways so that the labels align like interlocking puzzle pieces. These run across the columns, so we can call them the “column data” of the final structure. Similarly, we can do the same for the genes, perhaps annotating the chromosome they’re on, and other identifiers, and use these as the “row data”.

This is the basic structure of the SummarizedExperiment, but all is not well.

Bioconductor leans heavily into the S4 object model, making use of multiple dispatch as well as object validation. For example, if I wanted to create a range of fake genomic locations I could use

gr    
##   (1)     chrX       1-6      *
##   (2)     chrX       2-6      *
##   (3)     chrX       3-6      *
##   (4)     chrX       4-6      *
##   (5)     chrX       5-6      *
##   (6)     chrX         6      *
##   -------
##   seqinfo: 1 sequence from an unspecified genome; no seqlengths

Nu, en dit is slechts een speelgoedvoorbeeld, als ik een aantal van deze in een
data.frame

d 

Hmmm… it looks like it unfolded and did something strange. It was expecting a vector, not … whatever gr is.

Not to worry, though - the Bioconductor ecosystem defines a DataFrame object that does know how to deal with S4 classes just fine (there will be a lot of R noise here, I can’t help that - lots of masking)

library(S4Vectors)
## Loading required package: stats4
## Loading required package: BiocGenerics
## 
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
## 
##     anyDuplicated, aperm, append, as.data.frame, basename, cbind,
##     colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
##     get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply,
##     match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
##     Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort,
##     table, tapply, union, unique, unsplit, which.max, which.min
## 
## Attaching package: 'S4Vectors'
## The following object is masked from 'package:utils':
## 
##     findMatches
## The following objects are masked from 'package:base':
## 
##     expand.grid, I, unname
DataFrame(a = 1:6, b = gr)
## DataFrame with 6 rows and 2 columns
##           a         b
##    
## 1         1  chrX:1-6
## 2         2  chrX:2-6
## 3         3  chrX:3-6
## 4         4  chrX:4-6
## 5         5  chrX:5-6
## 6         6    chrX:6

Je zou kunnen zeggen: "Hé, dat ziet er bekend uit! Het is een beetje als een tibble"en je hebt gelijk; de typen van elke kolom worden bovenaan weergegeven, en in het geval van de GRanges object, het is een niet-atomisch type, correct behandeld. Er zijn belangrijke verschillen vergeleken met een tibblehoewel. Belangrijk is dat we hier prima rijnamen aan kunnen toevoegen

DataFrame(a = 1:6, b = gr, row.names = paste0("range", 1:6))
## DataFrame with 6 rows and 2 columns
##                a         b
##         
## range1         1  chrX:1-6
## range2         2  chrX:2-6
## range3         3  chrX:3-6
## range4         4  chrX:4-6
## range5         5  chrX:5-6
## range6         6    chrX:6

Als we het object kapotmaken, zal het ons dit laten weten omdat S4 objectvalidatie uitvoert

a  
## 1         1           A
## 2         2           B
## 3         3           C
validObject(a)
## (1) TRUE
# look away, I'm not supposed to do this
names(a@listData)       
## 1                1                A
## 2                2                B
## 3                3                C
validObject(a)
## Error in validObject(a): invalid class "DFrame" object: 
##     column names should not be NULL

Dit is de juiste klasse voor onze voorbeeldmetadata

as(sample_metadata, "DataFrame")
## DataFrame with 3 rows and 2 columns
##                 name       age
##           
## sample_X         Jim        51
## sample_Y        Jack        53
## sample_Z         Joe        52

Perfect!

Als we kijken naar een actueel voorbeeld van een SummarizedExperimentbijvoorbeeld uit het {airway}-pakket dat de gelezen aantallen per gen vastlegt voor een gladde spiercellijn van de luchtwegen RNA-Seq-experiment

library("airway")
## Loading required package: SummarizedExperiment
## Loading required package: MatrixGenerics
## Loading required package: matrixStats
## 
## Attaching package: 'MatrixGenerics'
## The following objects are masked from 'package:matrixStats':
## 
##     colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
##     colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
##     colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
##     colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
##     colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
##     colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
##     colWeightedMeans, colWeightedMedians, colWeightedSds,
##     colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
##     rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
##     rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
##     rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
##     rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
##     rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
##     rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
##     rowWeightedSds, rowWeightedVars
## Loading required package: GenomicRanges
## Loading required package: IRanges
## Loading required package: GenomeInfoDb
## Loading required package: Biobase
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## 
## Attaching package: 'Biobase'
## The following object is masked from 'package:MatrixGenerics':
## 
##     rowMedians
## The following objects are masked from 'package:matrixStats':
## 
##     anyMissing, rowMedians
data("airway")
se 

we see a lot of information - the “dimensions” of this object is 63677 genes measured for 8 samples. The ‘rownames’ element shows the IDs of these genes which will link the ‘rowData’ to the counts assay rows, and the ‘colnames’ element shows the sample IDs which will link the ‘colData’ to the counts assay columns.

Pulling this apart…

cd        
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample
##                     
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677

we zien dat de sample-metadata bevat of het sample behandeld is of niet, en wat details over het experiment. Op dezelfde manier bevat de gen-metadata details over de verschillende ID's en genomische locaties.

rowData(se)(1:3, )
## DataFrame with 3 rows and 10 columns
##                         gene_id   gene_name  entrezid   gene_biotype
##                           
## ENSG00000000003 ENSG00000000003      TSPAN6        NA protein_coding
## ENSG00000000005 ENSG00000000005        TNMD        NA protein_coding
## ENSG00000000419 ENSG00000000419        DPM1        NA protein_coding
##                 gene_seq_start gene_seq_end    seq_name seq_strand
##                             
## ENSG00000000003       99883667     99894988           X         -1
## ENSG00000000005       99839799     99854882           X          1
## ENSG00000000419       49551404     49575092          20         -1
##                 seq_coord_system      symbol
##                         
## ENSG00000000003               NA      TSPAN6
## ENSG00000000005               NA        TNMD
## ENSG00000000419               NA        DPM1

Het verbinden van deze gegevens is de feitelijke analyse

assay(se)(1:5, 1:5)
##                 SRR1039508 SRR1039509 SRR1039512 SRR1039513 SRR1039516
## ENSG00000000003        679        448        873        408       1138
## ENSG00000000005          0          0          0          0          0
## ENSG00000000419        467        515        621        365        587
## ENSG00000000457        260        211        263        164        245
## ENSG00000000460         60         55         40         35         78

Het werkt allemaal heel goed: er zijn ook extra plekken om metagegevens over het experiment op te slaan die over de samples worden gedeeld, en metagegevens over de kolommen zelf.

mcols(colData(se))  
## SampleName    column 1      TRUE
## cell          column 2      TRUE
## dex           column 3     FALSE
## albut         column 4     FALSE
## Run           column 5      TRUE
## avgLength     column 6     FALSE
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE

Een DataFrame filteren

Nu komen we bij een heel interessant onderdeel: we willen een analyse uitvoeren op deze gegevens.

Eerst willen we kijken naar de monsters die onbehandeld waren. DataFrame maakt gebruik van hetzelfde ( subsetmechanisme als een data.frame zodat we konden doen

cd(cd$dex == "untrt", c("SampleName", "avgLength"))
## DataFrame with 4 rows and 2 columns
##            SampleName avgLength
##               
## SRR1039508 GSM1275862       126
## SRR1039512 GSM1275866       126
## SRR1039516 GSM1275870       120
## SRR1039520 GSM1275874       101

of zelfs

subset(cd, dex == "untrt", select = c("SampleName", "avgLength"))
## DataFrame with 4 rows and 2 columns
##            SampleName avgLength
##               
## SRR1039508 GSM1275862       126
## SRR1039512 GSM1275866       126
## SRR1039516 GSM1275870       120
## SRR1039520 GSM1275874       101

en die werken prima.

Wat vaak kan gebeuren is dat u de data voor een specifiek sample wilt. Natuurlijk, die ID kan in een kolom worden gecodeerd, maar doorgaans worden de sample-identifiers gebruikt als de rijnamen van de colDatazodat we de gegevens voor monster “SRR1039512” kunnen verkrijgen met

cd("SRR1039512", )
## DataFrame with 1 row and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##                     
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
##            Experiment    Sample    BioSample
##                     
## SRR1039512  SRX384349 SRS508571 SAMN02422678

Wat echt leuk zou zijn, is om {dplyr} te kunnen gebruiken!

Laten we het proberen…

dplyr::filter(cd, dex == "untrt")
## Error in UseMethod("filter"): no applicable method for 'filter' applied to an object of class "c('DFrame', 'DataFrame', 'SimpleList', 'RectangularData', 'List', 'DataFrame_OR_NULL', 'Vector', 'list_OR_List', 'Annotated', 'vector_OR_Vector')"

Nee, het is niet gedefinieerd voor deze klasse.

Een van de meest voorkomende oplossingen hiervoor is om dit te converteren DataFrame naar een tibbleop welk punt, ja, {dplyr} zou moeten werken

tbl_untrt                                  
## 1 GSM1275862 N61311  untrt untrt SRR10395…       126 SRX384345  SRS50… SAMN0242…
## 2 GSM1275866 N052611 untrt untrt SRR10395…       126 SRX384349  SRS50… SAMN0242…
## 3 GSM1275870 N080611 untrt untrt SRR10395…       120 SRX384353  SRS50… SAMN0242…
## 4 GSM1275874 N061011 untrt untrt SRR10395…       101 SRX384357  SRS50… SAMN0242…

Dat werkt, maar er zijn twee problemen: beide zijn dat we nu een
tibbleten eerste omdat het nu geen rijnamen meer heeft, en ten tweede omdat we het als gevolg daarvan niet meer in de SummarizedExperiment.

Wij hebben hetzelfde probleem met de geninformatie – wij kan omzetten naar tibble
en gebruik {dplyr}, maar we zitten daar vast

dplyr::filter(tibble::as_tibble(rowData(airway)), symbol == "CD38")
## # A tibble: 1 × 10
##   gene_id   gene_name entrezid gene_biotype gene_seq_start gene_seq_end seq_name
##                                              
## 1 ENSG0000… CD38            NA protein_cod…       15779898     15854853 4       
## # ℹ 3 more variables: seq_strand , seq_coord_system , symbol 

Kritisch, tibble heeft last van hetzelfde gebrek aan S4-ondersteuning als de gewone data.frames, dus als er Zijn een van deze kolommen, zal deze workflow verbreken

d 
## 1     1
d$grX  object.

Wat kunnen we nog meer doen?

Natuurlijk heb ik een voorgestelde oplossing

Laten we een knorrige DataFrame met S4 kolommen en rijnamen

m     
## Mazda RX4                 6       110         1         4       160
## Mazda RX4 Wag             6       110         1         4       160
## Datsun 710                4        93         1         4       108
## Hornet 4 Drive            6       110         0         3       258
## Hornet Sportabout         8       175         0         3       360
## ...                     ...       ...       ...       ...       ...
## Lotus Europa              4       113         1         5      95.1
## Ford Pantera L            8       264         1         5     351.0
## Ferrari Dino              6       175         1         5     145.0
## Maserati Bora             8       335         1         5     301.0
## Volvo 142E                4       109         1         4     121.0
d$grX       
## Mazda RX4                 6       110         1         4       160  chrX:1-10
## Mazda RX4 Wag             6       110         1         4       160  chrX:2-11
## Datsun 710                4        93         1         4       108  chrX:3-12
## Hornet 4 Drive            6       110         0         3       258  chrX:4-13
## Hornet Sportabout         8       175         0         3       360  chrX:5-14
## ...                     ...       ...       ...       ...       ...        ...
## Lotus Europa              4       113         1         5      95.1 chrX:28-37
## Ford Pantera L            8       264         1         5     351.0 chrX:29-38
## Ferrari Dino              6       175         1         5     145.0 chrX:30-39
## Maserati Bora             8       335         1         5     301.0 chrX:31-40
## Volvo 142E                4       109         1         4     121.0 chrX:32-41
##                          grY                    nl
##                             
## Mazda RX4          chrY:1-10    1.94,0.80,1.02,...
## Mazda RX4 Wag      chrY:2-11  0.90, 1.52,-0.46,...
## Datsun 710         chrY:3-12    1.64,0.47,0.66,...
## Hornet 4 Drive     chrY:4-13      0.06, 1.93,-1.11
## Hornet Sportabout  chrY:5-14     -1.01,-0.77,-0.04
## ...                      ...                   ...
## Lotus Europa      chrY:28-37 -0.22, 0.66,-1.10,...
## Ford Pantera L    chrY:29-38 -1.38, 0.74, 1.24,...
## Ferrari Dino      chrY:30-39 -0.81, 1.10, 0.85,...
## Maserati Bora     chrY:31-40    1.59,0.65,1.32,...
## Volvo 142E        chrY:32-41    1.07,0.78,0.00,...

en voeg wat meer metadata toe over de colData kolommen

mcols(colData(se))  
## SampleName    column 1      TRUE
## cell          column 2      TRUE
## dex           column 3     FALSE
## albut         column 4     FALSE
## Run           column 5      TRUE
## avgLength     column 6     FALSE
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE

Mijn oplossing was om de {dplyr}-werkwoorden op een manier te schrijven die compatibel was met DataFrame
maar die vermijdt door een tibble waar mogelijk. Dat werd {DFplyr} en het heeft de afgelopen 5 jaar op GitHub gestaan ​​zonder veel te doen.

Ik heb een eerste versie van dit pakket geschreven, ondanks dat ik nogal naïef was over de daadwerkelijke implementatie ervan. DataFramedus ik ben Michael Lawrence en Hervé Pagès erg dankbaar dat ze hebben geholpen de compatibiliteit te verbeteren en op bugs hebben gewezen in wat ik had gedaan.

Tijd voor een rondleiding

library(DFplyr)
## Loading required package: dplyr
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:Biobase':
## 
##     combine
## The following objects are masked from 'package:GenomicRanges':
## 
##     intersect, setdiff, union
## The following object is masked from 'package:GenomeInfoDb':
## 
##     intersect
## The following objects are masked from 'package:IRanges':
## 
##     collapse, desc, intersect, setdiff, slice, union
## The following object is masked from 'package:matrixStats':
## 
##     count
## The following objects are masked from 'package:S4Vectors':
## 
##     first, intersect, rename, setdiff, setequal, union
## The following objects are masked from 'package:BiocGenerics':
## 
##     combine, intersect, setdiff, union
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## Warning: replacing previous import 'S4Vectors::rename' by 'dplyr::rename' when
## loading 'DFplyr'
## 
## Attaching package: 'DFplyr'
## The following objects are masked from 'package:dplyr':
## 
##     count, desc
## The following objects are masked from 'package:IRanges':
## 
##     desc, slice
## The following object is masked from 'package:matrixStats':
## 
##     count
## The following object is masked from 'package:stats':
## 
##     filter
colData(se)
## DataFrame with 8 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##                     
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample
##                     
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677
cd 

One thing I added was a custom ‘label’ if you’re using this package within RStudio, in which case the Environment pane will show cd as “Formal class DataFrame (dplyr-compatible)”. That’s not a change in the object itself, but rather all DataFrame objects will now show this, because {dplyr} verbs should work on them.

Now I can just filter the colData as if it was a data.frame or a tibble, but the result is still a DataFrame

treated        
## SRR1039509 GSM1275863  N61311       trt    untrt SRR1039509       126
## SRR1039513 GSM1275867  N052611      trt    untrt SRR1039513        87
## SRR1039517 GSM1275871  N080611      trt    untrt SRR1039517       126
## SRR1039521 GSM1275875  N061011      trt    untrt SRR1039521        98
##            Experiment    Sample    BioSample
##                     
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039521  SRX384358 SRS508580 SAMN02422677

Belangrijk is dat de rijnamen en metagegevens volledig behouden blijven, relevant voor deze gefilterde subset

rownames(treated)
## (1) "SRR1039509" "SRR1039513" "SRR1039517" "SRR1039521"
mcols(treated)
## DataFrame with 9 rows and 2 columns
##               position     is_ID
##             
## SampleName    column 1      TRUE
## cell          column 2      TRUE
## dex           column 3     FALSE
## albut         column 4     FALSE
## Run           column 5      TRUE
## avgLength     column 6     FALSE
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE
exp        
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677
mcols(exp)
## DataFrame with 3 rows and 2 columns
##               position     is_ID
##             
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE

Ik kan toevoegen meer voorbeeldgegevens als ik die heb

cdq        
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample   quality
##                      
## SRR1039508  SRX384345 SRS508568 SAMN02422669  0.386436
## SRR1039509  SRX384346 SRS508567 SAMN02422675  0.566096
## SRR1039512  SRX384349 SRS508571 SAMN02422678  0.327839
## SRR1039513  SRX384350 SRS508572 SAMN02422670  0.744911
## SRR1039516  SRX384353 SRS508575 SAMN02422682  0.331616
## SRR1039517  SRX384354 SRS508576 SAMN02422673  0.728328
## SRR1039520  SRX384357 SRS508579 SAMN02422683  0.626803
## SRR1039521  SRX384358 SRS508580 SAMN02422677  0.248757
mcols(cdq)
## DataFrame with 10 rows and 2 columns
##               position     is_ID
##             
## SampleName    column 1      TRUE
## cell          column 2      TRUE
## dex           column 3     FALSE
## albut         column 4     FALSE
## Run           column 5      TRUE
## avgLength     column 6     FALSE
## Experiment    column 7      TRUE
## Sample        column 8      TRUE
## BioSample     column 9      TRUE
## quality             NA        NA

en omdat er geen metagegevens over deze nieuwe kolom beschikbaar waren, heeft deze een lege rij in de mcols binnenkomst.

Als ik een bewerking uitvoer die qua rijnamen niet logisch is, zullen
worden verwijderd

cdq |> 
  group_by(dex) |> 
  summarise(avg_quality = mean(quality))
##     dex avg_quality
## 1   trt   0.5720231
## 2 untrt   0.4181736

maar het is prima om ze opnieuw te ordenen

cdq |> 
  arrange(desc(quality)) |> 
  slice(1:4)
## DataFrame with 4 rows and 10 columns
##            SampleName     cell      dex    albut        Run avgLength
##                     
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
##            Experiment    Sample    BioSample   quality
##                      
## SRR1039513  SRX384350 SRS508572 SAMN02422670  0.744911
## SRR1039517  SRX384354 SRS508576 SAMN02422673  0.728328
## SRR1039520  SRX384357 SRS508579 SAMN02422683  0.626803
## SRR1039509  SRX384346 SRS508567 SAMN02422675  0.566096

Eén ding dat DataFrame mist - net als data.frame - is het concept van groepen. {tibble} loste dit op door een "groups" attribuut, dus ik deed hetzelfde in {DFplyr} - ik bezit {S4Vectors} niet, dus ik moest een aantal functies maskeren om deze ondersteuning in te bouwen. Ik kan nu gegroepeerde bewerkingen uitvoeren op een DataFrame en laat de groeperingsinformatie afdrukken zoals {tibble} dat doet

cd |> 
  group_by(dex) 
## DataFrame with 8 rows and 9 columns
## Groups:  dex 
##            SampleName     cell      dex    albut        Run avgLength
##                     
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample
##                     
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677
cd |> 
  group_by(dex) |> 
  summarise(meanAvgLength = mean(avgLength))
##     dex meanAvgLength
## 1   trt        109.25
## 2 untrt        118.25

Als ik probeer de subset "terug te zetten" colData Ik krijg een foutmelding, omdat er assaygegevens zijn voor monsters die we hebben verwijderd

colData(se)
## DataFrame with 8 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##                     
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039509 GSM1275863  N61311     trt      untrt SRR1039509       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039513 GSM1275867  N052611    trt      untrt SRR1039513        87
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039517 GSM1275871  N080611    trt      untrt SRR1039517       126
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
## SRR1039521 GSM1275875  N061011    trt      untrt SRR1039521        98
##            Experiment    Sample    BioSample
##                     
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039520  SRX384357 SRS508579 SAMN02422683
## SRR1039521  SRX384358 SRS508580 SAMN02422677
treated
## DataFrame with 4 rows and 9 columns
##            SampleName     cell      dex    albut        Run avgLength
##                     
## SRR1039509 GSM1275863  N61311       trt    untrt SRR1039509       126
## SRR1039513 GSM1275867  N052611      trt    untrt SRR1039513        87
## SRR1039517 GSM1275871  N080611      trt    untrt SRR1039517       126
## SRR1039521 GSM1275875  N061011      trt    untrt SRR1039521        98
##            Experiment    Sample    BioSample
##                     
## SRR1039509  SRX384346 SRS508567 SAMN02422675
## SRR1039513  SRX384350 SRS508572 SAMN02422670
## SRR1039517  SRX384354 SRS508576 SAMN02422673
## SRR1039521  SRX384358 SRS508580 SAMN02422677
colData(se) 

But as long as I have some metadata for all the samples, it’s fine - cdq was the version of colData with quality information, and you can see it’s incorporated on the last line of this output

colData(se) 

Storing S4 classes isn’t all we can do - performing {dplyr} operations on S4 columns is perfectly fine; here, adding more S4 columns based on others

myrange       
## Mazda RX4                 6       110         1         4       160  chrX:1-10
## Mazda RX4 Wag             6       110         1         4       160  chrX:2-11
## Datsun 710                4        93         1         4       108  chrX:3-12
## Hornet 4 Drive            6       110         0         3       258  chrX:4-13
## Hornet Sportabout         8       175         0         3       360  chrX:5-14
## ...                     ...       ...       ...       ...       ...        ...
## Lotus Europa              4       113         1         5      95.1 chrX:28-37
## Ford Pantera L            8       264         1         5     351.0 chrX:29-38
## Ferrari Dino              6       175         1         5     145.0 chrX:30-39
## Maserati Bora             8       335         1         5     301.0 chrX:31-40
## Volvo 142E                4       109         1         4     121.0 chrX:32-41
##                          grY                    nl  overlaps   quality
##                               
## Mazda RX4          chrY:1-10    1.94,0.80,1.02,...         4  0.144992
## Mazda RX4 Wag      chrY:2-11  0.90, 1.52,-0.46,...         4  0.726243
## Datsun 710         chrY:3-12    1.64,0.47,0.66,...         4  0.146000
## Hornet 4 Drive     chrY:4-13      0.06, 1.93,-1.11         4  0.695177
## Hornet Sportabout  chrY:5-14     -1.01,-0.77,-0.04         4  0.921556
## ...                      ...                   ...       ...       ...
## Lotus Europa      chrY:28-37 -0.22, 0.66,-1.10,...         0  0.371289
## Ford Pantera L    chrY:29-38 -1.38, 0.74, 1.24,...         0  0.420842
## Ferrari Dino      chrY:30-39 -0.81, 1.10, 0.85,...         0  0.890471
## Maserati Bora     chrY:31-40    1.59,0.65,1.32,...         0  0.395305
## Volvo 142E        chrY:32-41    1.07,0.78,0.00,...         0  0.532688
##                      nearest
##                    
## Mazda RX4          chrX:1-10
## Mazda RX4 Wag      chrX:2-11
## Datsun 710         chrX:3-12
## Hornet 4 Drive     chrX:4-13
## Hornet Sportabout  chrX:5-14
## ...                      ...
## Lotus Europa      chrX:28-37
## Ford Pantera L    chrX:29-38
## Ferrari Dino      chrX:30-39
## Maserati Bora     chrX:31-40
## Volvo 142E        chrX:32-41

of rijen filteren

d |> 
  arrange(desc(quality)) |> 
  filter(overlaps > 0) |> 
  slice(1:4)
## DataFrame with 4 rows and 11 columns
##                         cyl        hp        am      gear      disp        grX
##                         
## Merc 280C                 6       123         0         4     167.6 chrX:11-20
## Merc 450SL                8       180         0         3     275.8 chrX:13-22
## Merc 450SE                8       180         0         3     275.8 chrX:12-21
## Hornet Sportabout         8       175         0         3     360.0  chrX:5-14
##                          grY                    nl  overlaps   quality
##                               
## Merc 280C         chrY:11-20 -0.08, 0.55,-0.59,...         4  0.990185
## Merc 450SL        chrY:13-22      1.23,-0.35, 0.04         2  0.979190
## Merc 450SE        chrY:12-21      2.60, 0.98,-1.50         3  0.958658
## Hornet Sportabout  chrY:5-14     -1.01,-0.77,-0.04         4  0.921556
##                      nearest
##                    
## Merc 280C         chrX:11-20
## Merc 450SL        chrX:13-22
## Merc 450SE        chrX:12-21
## Hornet Sportabout  chrX:5-14

Het is niet per se nodig om de DataFrame in een variabele, ofwel - direct met de extractie werken kan in sommige gevallen schoner zijn

count(colData(se), cell)
## DataFrame with 4 rows and 2 columns
##       cell         n
##    
## 1  N052611         2
## 2  N061011         2
## 3  N080611         2
## 4  N61311          2











Andere manieren om te filteren

Het gebruik van {dplyr}-syntaxis op een DataFrame is erg handig, maar dat is slechts een onderdeel van een SummarizedExperiment – het zou geweldig zijn om dit verder uit te kunnen breiden en zoiets te doen

filter(airway, rows = ..., cols = ...)

Het is mogelijk om zoiets te doen – als ik ID’s genereer van de ‘rijen’ en ‘kolommen’ waar ik een subset van wil maken, kan ik deze doorgeven aan een ( extractie

untrt  filter(dex == "untrt") |> rownames()
untrt
## (1) "SRR1039508" "SRR1039512" "SRR1039516" "SRR1039520"
genes  rownames()
genes
## (1) "ENSG00000000003" "ENSG00000000005" "ENSG00000000419" "ENSG00000001036"
## (5) "ENSG00000001084" "ENSG00000001167"
airway_sub        
## SRR1039508 GSM1275862  N61311     untrt    untrt SRR1039508       126
## SRR1039512 GSM1275866  N052611    untrt    untrt SRR1039512       126
## SRR1039516 GSM1275870  N080611    untrt    untrt SRR1039516       120
## SRR1039520 GSM1275874  N061011    untrt    untrt SRR1039520       101
##            Experiment    Sample    BioSample
##                     
## SRR1039508  SRX384345 SRS508568 SAMN02422669
## SRR1039512  SRX384349 SRS508571 SAMN02422678
## SRR1039516  SRX384353 SRS508575 SAMN02422682
## SRR1039520  SRX384357 SRS508579 SAMN02422683
rowData(airway_sub)
## DataFrame with 6 rows and 10 columns
##                         gene_id   gene_name  entrezid   gene_biotype
##                           
## ENSG00000000003 ENSG00000000003      TSPAN6        NA protein_coding
## ENSG00000000005 ENSG00000000005        TNMD        NA protein_coding
## ENSG00000000419 ENSG00000000419        DPM1        NA protein_coding
## ENSG00000001036 ENSG00000001036       FUCA2        NA protein_coding
## ENSG00000001084 ENSG00000001084        GCLC        NA protein_coding
## ENSG00000001167 ENSG00000001167        NFYA        NA protein_coding
##                 gene_seq_start gene_seq_end    seq_name seq_strand
##                             
## ENSG00000000003       99883667     99894988           X         -1
## ENSG00000000005       99839799     99854882           X          1
## ENSG00000000419       49551404     49575092          20         -1
## ENSG00000001036      143815948    143832827           6         -1
## ENSG00000001084       53362139     53481768           6         -1
## ENSG00000001167       41040684     41067715           6          1
##                 seq_coord_system      symbol
##                         
## ENSG00000000003               NA      TSPAN6
## ENSG00000000005               NA        TNMD
## ENSG00000000419               NA        DPM1
## ENSG00000001036               NA       FUCA2
## ENSG00000001084               NA        GCLC
## ENSG00000001167               NA        NFYA

Merk op dat dit nieuwe object nu slechts 6 genen en 4 samples heeft (het origineel had 63.677 genen en 8 samples).

Dit soort filtering is nog mooier in MultiAssayExperiment waar meerdere
SummarizedExperiments (of soortgelijke objecten) worden samengevoegd tot een superobject waarbij de colData kan relevant zijn voor monsters die in meerdere assays voorkomen.

MultiAssayExperiment-gegevensindelingMultiAssayExperiment-gegevensindeling

MultiAssayExperiment-gegevensindeling

MultiAssayExperiment heeft een aantal van de best geschreven vignetten die ik heb gezien, en ik raad ten zeerste aan om ze te lezen als je deze opmaak nodig hebt

library(MultiAssayExperiment)

(het object wordt niet afgebeeld)

mae  
## Jack              M        38
## Jill              F        39
## Bob               M        40
## Barbara           F        41

Het subsetten van de verschillende dimensies (rijen, kolommen, assays) kan worden gedaan met de volgende indeling

myMultiAssay(rows, columns, assays)

en sindsdien mae$x is gedefinieerd om een colData kolom, ik kan dit object subsetten naar metingen van twee genen in elke test voor alleen de mannelijke proefpersonen

mae(c("ENST00000355076", "ENST00000383323"), mae$sex == "M", )
## A MultiAssayExperiment object of 4 listed
##  experiments with user-defined names and respective classes.
##  Containing an ExperimentList class object of length 4:
##  (1) Affy: SummarizedExperiment with 2 rows and 2 columns
##  (2) Methyl450k: matrix with 2 rows and 3 columns
##  (3) RNASeqGene: matrix with 1 rows and 2 columns
##  (4) GISTIC: RangedSummarizedExperiment with 1 rows and 2 columns
## Functionality:
##  experiments() - obtain the ExperimentList instance
##  colData() - the primary/phenotype DataFrame
##  sampleMap() - the sample coordination DataFrame
##  `$`, `(`, `((` - extract colData columns, subset, or experiment
##  *Format() - convert into a long or wide DataFrame
##  assays() - convert ExperimentList to a SimpleList of matrices
##  exportClass() - save data to flat files

Dat alles brengt ons bij het tidyOmics-project dat erop gericht is om tidy-analysepakketten voor omics-data te creëren. Een van de pakketten is tidySummarizedExperiment wat een herformulering is van SummarizedExperiment in een ‘nette’ zin

# remotes::install_github("stemangiola/tidySummarizedExperiment")
tidySummarizedExperiment::pasilla
## # A SummarizedExperiment-tibble abstraction: 102,193 × 5
## # Features=14599 | Samples=7 | Assays=counts
##    .feature    .sample counts condition type      
##                          
##  1 FBgn0000003 untrt1       0 untreated single_end
##  2 FBgn0000008 untrt1      92 untreated single_end
##  3 FBgn0000014 untrt1       5 untreated single_end
##  4 FBgn0000015 untrt1       0 untreated single_end
##  5 FBgn0000017 untrt1    4664 untreated single_end
##  6 FBgn0000018 untrt1     583 untreated single_end
##  7 FBgn0000022 untrt1       0 untreated single_end
##  8 FBgn0000024 untrt1      10 untreated single_end
##  9 FBgn0000028 untrt1       0 untreated single_end
## 10 FBgn0000032 untrt1    1446 untreated single_end
## # ℹ 40 more rows

Als je al bekend bent met MultiAssayExperiment dan vind je dit misschien enigszins bekend longFormat uitvoer daar

longFormat(mae)
## DataFrame with 80 rows and 5 columns
##           assay     primary         rowname     colname     value
##             
## 1          Affy        Jack ENST00000294241      array1       101
## 2          Affy        Jack ENST00000355076      array1       102
## 3          Affy        Jack ENST00000383706      array1       103
## 4          Affy        Jack ENST00000234812      array1       104
## 5          Affy        Jack ENST00000383323      array1       105
## ...         ...         ...             ...         ...       ...
## 76       GISTIC        Jill ENST00000135411       samp2         0
## 77       GISTIC        Jill ENST00000135412       samp2         1
## 78       GISTIC        Jill ENST00000135413       samp2         0
## 79       GISTIC        Jill ENST00000135414       samp2         1
## 80       GISTIC        Jill ENST00000383323       samp2         0

Samenvatting

Dat was een beetje langdradig, maar ik wilde al een tijdje mijn liefde voor rijnamen, die voortkomt uit deze Bioconductor-benadering, uitspellen. {DFplyr} is intern een beetje een rommeltje, maar ik geloof dat het veelbelovend is om nuttig te zijn, dus ik ben geïnteresseerd in use-cases, failure modes, etc… Het tidyOmics-project definieert veel nieuwe structuren die moeten interacteren met DataFrames en ik ben er redelijk zeker van dat {DFplyr} daarbij kan helpen.

Als u opmerkingen, suggesties of verbeteringen hebt – of als u denkt dat {DFplyr} nuttig voor u zou kunnen zijn, kunt u dat doen in de onderstaande opmerkingensectie of contact met mij opnemen via Mastodon.

devtools::sessie_info()
## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value
##  version  R version 4.3.3 (2024-02-29)
##  os       Pop!_OS 22.04 LTS
##  system   x86_64, linux-gnu
##  ui       X11
##  language (EN)
##  collate  en_AU.UTF-8
##  ctype    en_AU.UTF-8
##  tz       Australia/Adelaide
##  date     2024-08-11
##  pandoc   3.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package                  * version     date (UTC) lib source
##  abind                      1.4-5       2016-07-21 (1) CRAN (R 4.3.3)
##  airway                   * 1.22.0      2023-10-26 (1) Bioconductor
##  Biobase                  * 2.62.0      2023-10-24 (1) Bioconductor
##  BiocBaseUtils              1.4.0       2023-10-24 (1) Bioconductor
##  BiocGenerics             * 0.48.1      2023-11-01 (1) Bioconductor
##  BiocIO                     1.12.0      2023-10-24 (1) Bioconductor
##  BiocParallel               1.36.0      2023-10-24 (1) Bioconductor
##  Biostrings                 2.70.3      2024-03-13 (1) Bioconductor 3.18 (R 4.3.3)
##  bitops                     1.0-7       2021-04-24 (1) CRAN (R 4.3.2)
##  blogdown                   1.19        2024-02-01 (1) CRAN (R 4.3.3)
##  bookdown                   0.36        2023-10-16 (1) CRAN (R 4.3.2)
##  bslib                      0.6.1       2023-11-28 (3) CRAN (R 4.3.2)
##  cachem                     1.0.8       2023-05-01 (3) CRAN (R 4.3.0)
##  callr                      3.7.3       2022-11-02 (3) CRAN (R 4.2.2)
##  charcuterie              * 0.0.2       2024-08-07 (1) local
##  cli                        3.6.1       2023-03-23 (1) CRAN (R 4.3.3)
##  codetools                  0.2-19      2023-02-01 (4) CRAN (R 4.2.2)
##  colorspace                 2.1-0       2023-01-23 (1) CRAN (R 4.3.3)
##  crayon                     1.5.2       2022-09-29 (3) CRAN (R 4.2.1)
##  data.table                 1.15.0      2024-01-30 (3) CRAN (R 4.3.2)
##  DelayedArray               0.28.0      2023-10-24 (1) Bioconductor
##  devtools                   2.4.5       2022-10-11 (1) CRAN (R 4.3.2)
##  DFplyr                   * 0.0.1.9000  2024-08-11 (1) local
##  digest                     0.6.34      2024-01-11 (3) CRAN (R 4.3.2)
##  dplyr                    * 1.1.4       2023-11-17 (3) CRAN (R 4.3.2)
##  ellipsis                   0.3.2       2021-04-29 (3) CRAN (R 4.1.1)
##  evaluate                   0.23        2023-11-01 (3) CRAN (R 4.3.2)
##  fansi                      1.0.6       2023-12-08 (1) CRAN (R 4.3.3)
##  fastmap                    1.1.1       2023-02-24 (3) CRAN (R 4.2.2)
##  fs                         1.6.3       2023-07-20 (3) CRAN (R 4.3.1)
##  generics                   0.1.3       2022-07-05 (3) CRAN (R 4.2.1)
##  GenomeInfoDb             * 1.38.8      2024-03-15 (1) Bioconductor 3.18 (R 4.3.3)
##  GenomeInfoDbData           1.2.11      2024-06-21 (1) Bioconductor
##  GenomicAlignments          1.38.2      2024-01-16 (1) Bioconductor 3.18 (R 4.3.3)
##  GenomicRanges            * 1.54.1      2023-10-29 (1) Bioconductor
##  ggplot2                    3.5.1       2024-04-23 (1) CRAN (R 4.3.3)
##  glue                       1.7.0       2024-01-09 (1) CRAN (R 4.3.3)
##  gtable                     0.3.5       2024-04-22 (1) CRAN (R 4.3.3)
##  htmltools                  0.5.7       2023-11-03 (3) CRAN (R 4.3.2)
##  htmlwidgets                1.6.2       2023-03-17 (1) CRAN (R 4.3.2)
##  httpuv                     1.6.12      2023-10-23 (1) CRAN (R 4.3.2)
##  httr                       1.4.7       2023-08-15 (3) CRAN (R 4.3.1)
##  icecream                   0.2.1       2023-09-27 (1) CRAN (R 4.3.2)
##  IRanges                  * 2.36.0      2023-10-24 (1) Bioconductor
##  jquerylib                  0.1.4       2021-04-26 (3) CRAN (R 4.1.2)
##  jsonlite                   1.8.8       2023-12-04 (3) CRAN (R 4.3.2)
##  knitr                      1.45        2023-10-30 (3) CRAN (R 4.3.2)
##  later                      1.3.1       2023-05-02 (1) CRAN (R 4.3.2)
##  lattice                    0.22-5      2023-10-24 (4) CRAN (R 4.3.1)
##  lazyeval                   0.2.2       2019-03-15 (1) CRAN (R 4.3.2)
##  lifecycle                  1.0.4       2023-11-07 (1) CRAN (R 4.3.3)
##  magrittr                   2.0.3       2022-03-30 (1) CRAN (R 4.3.3)
##  Matrix                     1.6-5       2024-01-11 (4) CRAN (R 4.3.3)
##  MatrixGenerics           * 1.14.0      2023-10-24 (1) Bioconductor
##  matrixStats              * 1.1.0       2023-11-07 (1) CRAN (R 4.3.2)
##  memoise                    2.0.1       2021-11-26 (3) CRAN (R 4.2.0)
##  mime                       0.12        2021-09-28 (3) CRAN (R 4.2.0)
##  miniUI                     0.1.1.1     2018-05-18 (1) CRAN (R 4.3.2)
##  MultiAssayExperiment     * 1.28.0      2023-10-24 (1) Bioconductor
##  munsell                    0.5.1       2024-04-01 (1) CRAN (R 4.3.3)
##  pillar                     1.9.0       2023-03-22 (1) CRAN (R 4.3.3)
##  pkgbuild                   1.4.2       2023-06-26 (1) CRAN (R 4.3.2)
##  pkgconfig                  2.0.3       2019-09-22 (1) CRAN (R 4.3.3)
##  pkgload                    1.3.3       2023-09-22 (1) CRAN (R 4.3.2)
##  plotly                     4.10.4      2024-01-13 (1) CRAN (R 4.3.3)
##  plyranges                  1.22.0      2023-10-24 (1) Bioconductor
##  prettyunits                1.2.0       2023-09-24 (3) CRAN (R 4.3.1)
##  processx                   3.8.3       2023-12-10 (3) CRAN (R 4.3.2)
##  profvis                    0.3.8       2023-05-02 (1) CRAN (R 4.3.2)
##  promises                   1.2.1       2023-08-10 (1) CRAN (R 4.3.2)
##  ps                         1.7.6       2024-01-18 (3) CRAN (R 4.3.2)
##  purrr                      1.0.2       2023-08-10 (3) CRAN (R 4.3.1)
##  R6                         2.5.1       2021-08-19 (1) CRAN (R 4.3.3)
##  Rcpp                       1.0.11      2023-07-06 (1) CRAN (R 4.3.2)
##  RCurl                      1.98-1.14   2024-01-09 (1) CRAN (R 4.3.3)
##  remotes                    2.4.2.1     2023-07-18 (1) CRAN (R 4.3.2)
##  restfulr                   0.0.15      2022-06-16 (1) CRAN (R 4.3.3)
##  rjson                      0.2.21      2022-01-09 (1) CRAN (R 4.3.3)
##  rlang                      1.1.4       2024-06-04 (1) CRAN (R 4.3.3)
##  rmarkdown                  2.25        2023-09-18 (3) CRAN (R 4.3.1)
##  Rsamtools                  2.18.0      2023-10-24 (1) Bioconductor
##  rstudioapi                 0.15.0      2023-07-07 (3) CRAN (R 4.3.1)
##  rtracklayer                1.62.0      2023-10-24 (1) Bioconductor
##  S4Arrays                   1.2.1       2024-03-04 (1) Bioconductor 3.18 (R 4.3.3)
##  S4Vectors                * 0.40.2      2023-11-23 (1) Bioconductor 3.18 (R 4.3.3)
##  sass                       0.4.8       2023-12-06 (3) CRAN (R 4.3.2)
##  scales                     1.3.0       2023-11-28 (1) CRAN (R 4.3.2)
##  sessioninfo                1.2.2       2021-12-06 (1) CRAN (R 4.3.2)
##  shiny                      1.7.5.1     2023-10-14 (1) CRAN (R 4.3.2)
##  SparseArray                1.2.4       2024-02-11 (1) Bioconductor 3.18 (R 4.3.3)
##  stringi                    1.8.3       2023-12-11 (3) CRAN (R 4.3.2)
##  stringr                    1.5.1       2023-11-14 (3) CRAN (R 4.3.2)
##  SummarizedExperiment     * 1.32.0      2023-10-24 (1) Bioconductor
##  tibble                     3.2.1       2023-03-20 (1) CRAN (R 4.3.3)
##  tidyr                      1.3.1       2024-01-24 (3) CRAN (R 4.3.2)
##  tidyselect                 1.2.0       2022-10-10 (3) CRAN (R 4.2.1)
##  tidySummarizedExperiment   1.15.1      2024-08-06 (1) Github (stemangiola/tidySummarizedExperiment@4b8a4e1)
##  ttservice                  0.4.1       2024-06-07 (1) CRAN (R 4.3.3)
##  urlchecker                 1.0.1       2021-11-30 (1) CRAN (R 4.3.2)
##  usethis                    3.0.0       2024-07-29 (1) CRAN (R 4.3.3)
##  utf8                       1.2.4       2023-10-22 (1) CRAN (R 4.3.3)
##  vctrs                      0.6.5       2023-12-01 (1) CRAN (R 4.3.3)
##  viridisLite                0.4.2       2023-05-02 (1) CRAN (R 4.3.3)
##  withr                      3.0.0       2024-01-16 (1) CRAN (R 4.3.3)
##  xfun                       0.41        2023-11-01 (3) CRAN (R 4.3.2)
##  XML                        3.99-0.16.1 2024-01-22 (1) CRAN (R 4.3.3)
##  xtable                     1.8-4       2019-04-21 (1) CRAN (R 4.3.2)
##  XVector                    0.42.0      2023-10-24 (1) Bioconductor
##  yaml                       2.3.8       2023-12-11 (3) CRAN (R 4.3.2)
##  zlibbioc                   1.48.2      2024-03-13 (1) Bioconductor 3.18 (R 4.3.3)
## 
##  (1) /home/jono/R/x86_64-pc-linux-gnu-library/4.3
##  (2) /usr/local/lib/R/site-library
##  (3) /usr/lib/R/site-library
##  (4) /usr/lib/R/library
## 
## ──────────────────────────────────────────────────────────────────────────────