New approach: Selbal

Selbal is an R package for selection of balances in microbiome compositional data. As described in Rivera-Pinto et al. 2018 Balances: a new perspective for microbiome analysis https://msystems.asm.org/content/3/4/e00053-18, selbal implements a forward-selection method for the identification of two groups of taxa whose relative abundance, or balance, is associated with the response variable of interest. See https://github.com/UVic-omics/selbal.

# Load "devtools" library (install it if needed)
 # library(devtools)

# Install "selbal""
#  install_github(repo = "UVic-omics/selbal")

load environmental Data

# Import metadata
metadata <-read.csv("~/Documents/gbru_fy18_rice_methane/march2020/metadata_biomassCH4_noRIL9.csv", header=TRUE)

Load taxonomic count data

# Import OTU counts
otudata<-read.table("~/Documents/gbru_fy18_rice_methane/march2020/otu_table.tsv", header=TRUE)
# Move feature ID to rownames
row.names(otudata)<-otudata$feature.id
otudata<-otudata[,-1]
# Sort columns by name
otudata<- otudata[, order(names(otudata))]
# load Taxonomy annotation 
taxa <- read.table("~/Documents/gbru_fy18_rice_methane/march2020/observation_meta_data.tsv", sep="\t", header=TRUE, quote = "")

#Filter data to specific taxonomic levels
cdata <-cbind(taxa,otudata)
library(dplyr)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(tidyr)

fd_long<- gather(cdata, sample, count, colnames(cdata)[10:105], factor_key=TRUE)

#group by family
fd_fam_tally <- fd_long[,c(7,10,11)] %>% group_by(taxonomy_5, sample) %>%  summarise(n = sum(count))
fd_fam_wide <- fd_fam_tally %>% pivot_wider(names_from= sample, values_from=n)
df_fam_wide<- as.data.frame(fd_fam_wide)
rownames(df_fam_wide)<- df_fam_wide[,1]
df_fam_wide<- df_fam_wide[,-1]

Filter data

#Define the geometric mean for all values greater than 0
geomean <- function(x) { exp(mean(log(x[x>0]))) }

# Create a function to filter rows by the proportion of nonzero samples and the geometric mean of the nonzero samples
prefilter <- function(x, zcutoff, mcutoff){
    nzvect <- apply(x, 1, function(y){
      ((sum(y>0)/length(y))> zcutoff) & (geomean(y)> mcutoff)
      })
    lowcounts <- t(as.data.frame(apply(x[!nzvect,],2,sum)))
    rownames(lowcounts)<-c("lowconts")
    df1 <-rbind(lowcounts, x[nzvect,])
    return(df1)
}

Run family level analysis

#filter taxa
otutaxa100<-prefilter(df_fam_wide, 0.5, 100)
# Construct covariates matrix
covariates1 <- data.frame(genotype=metadata$genotype, sumch4=log10(metadata$sum_ch4), dev=metadata$dev)
# Process 

#select D3 developmental stage 
d3cov <- covariates1[covariates1$dev=="D3",]
d3cov <- d3cov[1:30,]
d3rows <- as.numeric(rownames(d3cov))
d3otus_filtered <- otutaxa100[,d3rows]


# create model matrix for log10 of total methane
mm1 <- model.matrix(~ sumch4, d3cov)
library(selbal)
sbout<- selbal.cv(t(d3otus_filtered), d3cov$sumch4, n.iter=10, seed=234753)


############################################################### 
 STARTING selbal.cv FUNCTION 
###############################################################

#-------------------------------------------------------------# 
# ZERO REPLACEMENT . . .
Loading required package: MASS

Attaching package: ‘MASS’

The following object is masked from ‘package:dplyr’:

    select

Loading required package: NADA
Loading required package: survival

Attaching package: ‘NADA’

The following object is masked from ‘package:stats’:

    cor

Loading required package: truncnorm

, . . . FINISHED. 
#-------------------------------------------------------------#

#-------------------------------------------------------------# 
# Starting the cross - validation procedure . . .
sbout
$accuracy.nvar

$var.barplot

$global.plot
TableGrob (2 x 1) "arrange": 2 grobs

$global.plot2
TableGrob (2 x 1) "arrange": 2 grobs

$ROC.plot
NULL

$cv.tab

$cv.accuracy
 [1] 0.002196164 0.001584954 0.008468705 0.002888459 0.002589784 0.001143780 0.005728671 0.002428404 0.003209565 0.004745270 0.005433683 0.002540281 0.002808864 0.001804024 0.004018338
[16] 0.003645877 0.002620363 0.007321406 0.002308431 0.005934665 0.005683666 0.003990323 0.007266434 0.003994663 0.002468332 0.004055390 0.002135893 0.001932227 0.004274039 0.005223320
[31] 0.004103786 0.004483961 0.004330137 0.002490260 0.003030292 0.001593479 0.003938556 0.002550531 0.004408869 0.002772143 0.004321207 0.002297730 0.001778298 0.004970326 0.004858929
[46] 0.004765624 0.002910011 0.003723047 0.003273437 0.003432713

$global.balance

$glm

Call:  glm(formula = numy ~ ., family = f.class, data = U)

Coefficients:
(Intercept)           V1  
     5.9954       0.3728  

Degrees of Freedom: 29 Total (i.e. Null);  28 Residual
Null Deviance:      0.07472 
Residual Deviance: 0.03441  AIC: -112

$opt.nvar
[1] 2

#Results The results of SelBal analysi show that hte best correlated balance is the ratio of Moraxellaceae to Planctomycetaceae

LS0tCnRpdGxlOiAiU0VMQkFMIGFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIE5ldyBhcHByb2FjaDogU2VsYmFsCgpTZWxiYWwgaXMgYW4gUiBwYWNrYWdlIGZvciBzZWxlY3Rpb24gb2YgYmFsYW5jZXMgaW4gbWljcm9iaW9tZSBjb21wb3NpdGlvbmFsIGRhdGEuIEFzIGRlc2NyaWJlZCBpbiBSaXZlcmEtUGludG8gZXQgYWwuIDIwMTggQmFsYW5jZXM6IGEgbmV3IHBlcnNwZWN0aXZlIGZvciBtaWNyb2Jpb21lIGFuYWx5c2lzIGh0dHBzOi8vbXN5c3RlbXMuYXNtLm9yZy9jb250ZW50LzMvNC9lMDAwNTMtMTgsIHNlbGJhbCBpbXBsZW1lbnRzIGEgZm9yd2FyZC1zZWxlY3Rpb24gbWV0aG9kIGZvciB0aGUgaWRlbnRpZmljYXRpb24gb2YgdHdvIGdyb3VwcyBvZiB0YXhhIHdob3NlIHJlbGF0aXZlIGFidW5kYW5jZSwgb3IgYmFsYW5jZSwgaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSByZXNwb25zZSB2YXJpYWJsZSBvZiBpbnRlcmVzdC4gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9VVmljLW9taWNzL3NlbGJhbC4KIApgYGB7cn0KIyBMb2FkICJkZXZ0b29scyIgbGlicmFyeSAoaW5zdGFsbCBpdCBpZiBuZWVkZWQpCiAjIGxpYnJhcnkoZGV2dG9vbHMpCgojIEluc3RhbGwgInNlbGJhbCIiCiMgIGluc3RhbGxfZ2l0aHViKHJlcG8gPSAiVVZpYy1vbWljcy9zZWxiYWwiKQpgYGAKIAoKIyBsb2FkIGVudmlyb25tZW50YWwgRGF0YQpgYGB7cn0KIyBJbXBvcnQgbWV0YWRhdGEKbWV0YWRhdGEgPC1yZWFkLmNzdigifi9Eb2N1bWVudHMvZ2JydV9meTE4X3JpY2VfbWV0aGFuZS9tYXJjaDIwMjAvbWV0YWRhdGFfYmlvbWFzc0NINF9ub1JJTDkuY3N2IiwgaGVhZGVyPVRSVUUpCmBgYAoKIyBMb2FkIHRheG9ub21pYyBjb3VudCBkYXRhCmBgYHtyfQojIEltcG9ydCBPVFUgY291bnRzCm90dWRhdGE8LXJlYWQudGFibGUoIn4vRG9jdW1lbnRzL2dicnVfZnkxOF9yaWNlX21ldGhhbmUvbWFyY2gyMDIwL290dV90YWJsZS50c3YiLCBoZWFkZXI9VFJVRSkKIyBNb3ZlIGZlYXR1cmUgSUQgdG8gcm93bmFtZXMKcm93Lm5hbWVzKG90dWRhdGEpPC1vdHVkYXRhJGZlYXR1cmUuaWQKb3R1ZGF0YTwtb3R1ZGF0YVssLTFdCiMgU29ydCBjb2x1bW5zIGJ5IG5hbWUKb3R1ZGF0YTwtIG90dWRhdGFbLCBvcmRlcihuYW1lcyhvdHVkYXRhKSldCiMgbG9hZCBUYXhvbm9teSBhbm5vdGF0aW9uIAp0YXhhIDwtIHJlYWQudGFibGUoIn4vRG9jdW1lbnRzL2dicnVfZnkxOF9yaWNlX21ldGhhbmUvbWFyY2gyMDIwL29ic2VydmF0aW9uX21ldGFfZGF0YS50c3YiLCBzZXA9Ilx0IiwgaGVhZGVyPVRSVUUsIHF1b3RlID0gIiIpCgojRmlsdGVyIGRhdGEgdG8gc3BlY2lmaWMgdGF4b25vbWljIGxldmVscwpjZGF0YSA8LWNiaW5kKHRheGEsb3R1ZGF0YSkKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKCmZkX2xvbmc8LSBnYXRoZXIoY2RhdGEsIHNhbXBsZSwgY291bnQsIGNvbG5hbWVzKGNkYXRhKVsxMDoxMDVdLCBmYWN0b3Jfa2V5PVRSVUUpCgojZ3JvdXAgYnkgZmFtaWx5CmZkX2ZhbV90YWxseSA8LSBmZF9sb25nWyxjKDcsMTAsMTEpXSAlPiUgZ3JvdXBfYnkodGF4b25vbXlfNSwgc2FtcGxlKSAlPiUgIHN1bW1hcmlzZShuID0gc3VtKGNvdW50KSkKZmRfZmFtX3dpZGUgPC0gZmRfZmFtX3RhbGx5ICU+JSBwaXZvdF93aWRlcihuYW1lc19mcm9tPSBzYW1wbGUsIHZhbHVlc19mcm9tPW4pCmRmX2ZhbV93aWRlPC0gYXMuZGF0YS5mcmFtZShmZF9mYW1fd2lkZSkKcm93bmFtZXMoZGZfZmFtX3dpZGUpPC0gZGZfZmFtX3dpZGVbLDFdCmRmX2ZhbV93aWRlPC0gZGZfZmFtX3dpZGVbLC0xXQpgYGAKCiMgRmlsdGVyIGRhdGEKYGBge3J9CiNEZWZpbmUgdGhlIGdlb21ldHJpYyBtZWFuIGZvciBhbGwgdmFsdWVzIGdyZWF0ZXIgdGhhbiAwCmdlb21lYW4gPC0gZnVuY3Rpb24oeCkgeyBleHAobWVhbihsb2coeFt4PjBdKSkpIH0KCiMgQ3JlYXRlIGEgZnVuY3Rpb24gdG8gZmlsdGVyIHJvd3MgYnkgdGhlIHByb3BvcnRpb24gb2Ygbm9uemVybyBzYW1wbGVzIGFuZCB0aGUgZ2VvbWV0cmljIG1lYW4gb2YgdGhlIG5vbnplcm8gc2FtcGxlcwpwcmVmaWx0ZXIgPC0gZnVuY3Rpb24oeCwgemN1dG9mZiwgbWN1dG9mZil7CiAgICBuenZlY3QgPC0gYXBwbHkoeCwgMSwgZnVuY3Rpb24oeSl7CiAgICAgICgoc3VtKHk+MCkvbGVuZ3RoKHkpKT4gemN1dG9mZikgJiAoZ2VvbWVhbih5KT4gbWN1dG9mZikKICAgICAgfSkKICAgIGxvd2NvdW50cyA8LSB0KGFzLmRhdGEuZnJhbWUoYXBwbHkoeFshbnp2ZWN0LF0sMixzdW0pKSkKICAgIHJvd25hbWVzKGxvd2NvdW50cyk8LWMoImxvd2NvbnRzIikKICAgIGRmMSA8LXJiaW5kKGxvd2NvdW50cywgeFtuenZlY3QsXSkKICAgIHJldHVybihkZjEpCn0KYGBgCgoKIyBSdW4gZmFtaWx5IGxldmVsIGFuYWx5c2lzCmBgYHtyfQojZmlsdGVyIHRheGEKb3R1dGF4YTEwMDwtcHJlZmlsdGVyKGRmX2ZhbV93aWRlLCAwLjUsIDEwMCkKCmBgYAoKYGBge3J9CiMgQ29uc3RydWN0IGNvdmFyaWF0ZXMgbWF0cml4CmNvdmFyaWF0ZXMxIDwtIGRhdGEuZnJhbWUoZ2Vub3R5cGU9bWV0YWRhdGEkZ2Vub3R5cGUsIHN1bWNoND1sb2cxMChtZXRhZGF0YSRzdW1fY2g0KSwgZGV2PW1ldGFkYXRhJGRldikKIyBQcm9jZXNzIAoKI3NlbGVjdCBEMyBkZXZlbG9wbWVudGFsIHN0YWdlIApkM2NvdiA8LSBjb3ZhcmlhdGVzMVtjb3ZhcmlhdGVzMSRkZXY9PSJEMyIsXQpkM2NvdiA8LSBkM2NvdlsxOjMwLF0KZDNyb3dzIDwtIGFzLm51bWVyaWMocm93bmFtZXMoZDNjb3YpKQpkM290dXNfZmlsdGVyZWQgPC0gb3R1dGF4YTEwMFssZDNyb3dzXQoKCiMgY3JlYXRlIG1vZGVsIG1hdHJpeCBmb3IgbG9nMTAgb2YgdG90YWwgbWV0aGFuZQptbTEgPC0gbW9kZWwubWF0cml4KH4gc3VtY2g0LCBkM2NvdikKYGBgCgoKYGBge3J9CmxpYnJhcnkoc2VsYmFsKQpzYm91dDwtIHNlbGJhbC5jdih0KGQzb3R1c19maWx0ZXJlZCksIGQzY292JHN1bWNoNCwgbi5pdGVyPTEwLCBzZWVkPTIzNDc1MykKYGBgCgpgYGB7cn0Kc2JvdXQKCmBgYAoKI1Jlc3VsdHMgVGhlIHJlc3VsdHMgb2YgU2VsQmFsIGFuYWx5c2kgc2hvdyB0aGF0IGh0ZSBiZXN0IGNvcnJlbGF0ZWQgYmFsYW5jZSBpcyB0aGUgcmF0aW8gb2YgTW9yYXhlbGxhY2VhZSB0byBQbGFuY3RvbXljZXRhY2VhZQo=