Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d2fd02c
Merge remote-tracking branch 'refs/remotes/simonsfoundation/master'
Jul 17, 2016
df8b0e3
refactorTFA
Jul 21, 2016
4bc3c3a
refactor tfa in python
Jul 22, 2016
5e57922
refactor tfa in python
Jul 22, 2016
004774a
TFA refactor class
Jul 24, 2016
cc62f7c
tfa indentation
Jul 25, 2016
8272df5
delete artifact
Jul 25, 2016
5ee2709
specify tfa parameter annotations
Jul 26, 2016
35b184b
wrote scaffolding for 3 quick tests and fixed obvious nomenclature is…
NicoDeVeaux Aug 3, 2016
938dcbe
refactored out the setup function so it can be easily changed. and ad…
NicoDeVeaux Aug 3, 2016
86f8343
rename to 3x2, which is the actual size of the expression matrix
NicoDeVeaux Aug 3, 2016
0b4041d
Merge pull request #1 from nickdeveaux/ndv_tfa
Aug 3, 2016
7c3f557
fix naming issue
Aug 3, 2016
7933331
add tfa unittest from Nick
Aug 3, 2016
10b69b4
tests for a variety of conditions to tfa calculation
NicoDeVeaux Aug 4, 2016
1f79f93
since no_self should be True, according to the B. Subtilis paper, rem…
NicoDeVeaux Aug 4, 2016
634d070
new tests for different cases of dup_self and different sized prior m…
NicoDeVeaux Aug 9, 2016
83702d1
Merge pull request #2 from nickdeveaux/ndv_tfa
Aug 9, 2016
c6ea1d8
test setup_max
Aug 9, 2016
c077faa
some refactoring of tfa.py
NicoDeVeaux Aug 9, 2016
16e9cd8
rename of flag
NicoDeVeaux Aug 9, 2016
be448f7
Merge branch 'master' of github.com:ryi06/inferelator_ng into ndv_tfa
NicoDeVeaux Aug 9, 2016
70f1838
remove pdb
NicoDeVeaux Aug 9, 2016
7614e54
increase the units in the last place
NicoDeVeaux Aug 9, 2016
b4fc1a2
replace tabs with spaces
NicoDeVeaux Aug 9, 2016
4d12454
added absolute tolerance to 1e-15
NicoDeVeaux Aug 9, 2016
77e94d8
tfa.py updated to use full words in variable names and have more comm…
NicoDeVeaux Aug 10, 2016
c1b9ff4
tfa tests updated by renaming for clarity
NicoDeVeaux Aug 10, 2016
51b942e
added comments and removed unnecessary call tolist()
NicoDeVeaux Aug 10, 2016
460182c
new test that fails
NicoDeVeaux Aug 10, 2016
0be2753
Merge pull request #3 from nickdeveaux/ndv_tfa
Aug 10, 2016
5adb291
modify tfa and test_tfa to handle tfs that have no prior or expressio…
Aug 10, 2016
c4cf28c
delete comment in test_tfa.py
Aug 10, 2016
9631128
delete additional comments
Aug 10, 2016
e17f6eb
remove tests that don't represent a valid use case
NicoDeVeaux Aug 11, 2016
96d4624
remove tests that don't represent a valid use case
NicoDeVeaux Aug 11, 2016
e4f20c7
no need to compute all-zero tfs if you have already computed non-zero…
NicoDeVeaux Aug 11, 2016
0495027
Merge pull request #4 from nickdeveaux/ndv_tfa_nonzero_tfs
Aug 11, 2016
f9b1512
remove num2words
NicoDeVeaux Aug 11, 2016
f228e65
Merge pull request #5 from nickdeveaux/ndv_tfa_nonzero_tfs
Aug 11, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions inferelator_ng/R_code/tfa.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@

# fix prior known interactions so the pseudoinverse does not fail
fix.pki <- function(pki) {
diag(pki)[apply(pki != 0, 2, sum) == 0] <- 1
# check for identical columns in pki
m <- ncol(pki)
fix.me <- T
while (fix.me) {
fix.me <- F
for (i in which(duplicated(pki, MARGIN=2))) {
for (j in 1:(i-1)) {
if(all(pki[, i] == pki[, j]) == TRUE) {
pki[i, i] <- 1
pki[j, j] <- 1
cat('Identical columns in rf (', i, j, ') fixed via self-interactions.\n')
fix.me <- T
}
}
}
}
return(pki)
}


# if noself is TRUE, all self-regulatory interactions are removed
# however, if dup.self is TRUE, self interactions for TFs that other TFs with the
# exact same set of interactions in the prior are kept
# the motivation for dup.self=TRUE is that TFs with identical prior should have
# identical TFA
tfa <- function(prior, exp.mat, exp.mat.halftau, noself=TRUE, dup.self=TRUE) {
tfwt <- apply(prior != 0, 2, sum) > 0

duplicates <- c()
if (dup.self) {
duplicates <- duplicated(prior[, tfwt], MARGIN=2) |
duplicated(prior[, tfwt], MARGIN=2, fromLast = TRUE)
duplicates <- colnames(prior)[tfwt][duplicates]
}

tfs <- setdiff(colnames(prior), duplicates)
tfs <- intersect(tfs, rownames(prior))
if (noself) {
diag(prior[tfs, tfs]) <- 0
}

activities <- matrix(0, ncol(prior), ncol(exp.mat.halftau),
dimnames=list(colnames(prior), colnames(exp.mat.halftau)))

if (any(tfwt)) {
require('corpcor')
activities[tfwt, ] <- pseudoinverse(prior[, tfwt, drop=FALSE]) %*% exp.mat.halftau
}

use.exp <- intersect(colnames(prior)[!tfwt], rownames(exp.mat))
activities[use.exp, ] <- exp.mat[use.exp, ]

return(activities)
}


tfa.bs <- function(prior, res.mat, des.mat) {
K <- 50
act.bs <- array(NA, dim=c(ncol(prior), ncol(res.mat), K))
cond <- ncol(res.mat)
for (k in 1:K) {
selected <- sample(cond, replace=T)
activities <- tfa(prior, res.mat[, selected], des.mat[, selected])
act.bs[,selected,k] <- activities
}
ret <- apply(act.bs, 1:2, median, na.rm=TRUE)
dimnames(ret) <- dimnames(activities)
return(ret)
}

tfa.nn <- function(prior, res.mat, des.mat, cores) {
require('nnls')
diag(prior) <- 0
#cor.mat <- cor(t(res.mat), t(res.mat[colnames(prior), ]))
#prior <- prior * sign(cor.mat)
#prior.fixed <- fix.pki(prior)

#dn <- dimnames(prior)
#prior <- refit.betas.mc(des.mat[colnames(prior), ], res.mat, prior)[, -1]
#dimnames(prior) <- dn
prior.fixed <- fix.pki(prior)

#abs.col.avg <- apply(abs(prior.fixed), 2, sum) / apply(prior.fixed != 0, 2, sum)
#abs.col.avg <- apply(prior.fixed, 2, sum) / apply(prior.fixed != 0, 2, sum)
#prior.fixed <- t(t(prior.fixed) / abs.col.avg)

des.mat <- matrix(0, ncol(prior), ncol(res.mat), dimnames=list(colnames(prior), colnames(res.mat)))
for (i in 1:ncol(res.mat)) {
des.mat[, i] <- nnls(prior.fixed, res.mat[, i])$x
}
return(des.mat)
}

collapse.activities <- function(activities, prior) {
tfs <- colnames(prior)
prior.noself <- prior
diag(prior.noself[tfs, tfs]) <- 0
noself.targets <- apply(prior.noself != 0, 2, sum)

dup <- which(duplicated(t(prior)) & apply(prior != 0, 2, sum) > 0)
while (length(dup) > 0) {
dup.cols <- which(apply(prior, 2, function(x) all(x==prior[, dup[1]])))
exemplar <- dup.cols[order(noself.targets[dup.cols], decreasing=TRUE)[1]]
print('collapse activities')
print(dup)
print(dup.cols)
print(exemplar)
for (dup.col in dup.cols) {
#activities[dup.cols, ] <- apply(activities[dup.cols, ], 2, mean)
activities[dup.col, ] <- activities[exemplar, ]
}
dup <- setdiff(dup, dup.cols)
}
return(activities)
}

# given a design and response matrix, refit the betas
# useful if we don't know whether the old betas came from scaled design and
# response matrices
refit.betas.mc <- function(X, Y, betas.old, cores) {
X <- rbind(1, X)
beta.rows <- mclapply(1:nrow(Y), refit.one, X, Y, betas.old, mc.cores=cores)
beta <- matrix(unlist(beta.rows), nrow(Y), byrow=TRUE)
return(beta=beta)
}

refit.one <- function(i, X, Y, betas.old) {
K <- nrow(X)
beta <- rep(0, K)
selected <- c(TRUE, betas.old[i, ] != 0)
x <- t(matrix(X[selected, ], sum(selected)))
coefs <- as.numeric(solve(crossprod(x), crossprod(x, Y[i, ])))
beta[selected] <- coefs
return(beta)
}

Empty file.
66 changes: 66 additions & 0 deletions inferelator_ng/tfa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import numpy as np
import pandas as pd
from scipy import linalg

class TFA:

"""
TFA calculates transcription factor activity using matrix pseudoinverse

Parameters
--------
prior: pd.dataframe
binary g by t matrix stating existence of gene-TF interactions.
g--gene, t--TF.

exp.mat: pd.dataframe

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update these parameter names

normalized expression matrix.

exp.mat.halftau: pd.dataframe
normalized expression matrix for time series.

noself=True: boolean
By default, self-regulatory interactions are removed.

dup_self=True: boolean
By default, self interactions for TFs that other TFs with the
exact same set of interactions in the prior are kept
"""

def __init__(self, prior, exp_mat, exp_mat_halftau):
self.prior = prior
self.exp_mat = exp_mat
self.exp_mat = exp_mat_halftau

def tfa(self, noself = True, dup_self = True):
tfwt = self.prior.abs().sum(axis = 0) > 0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use more descriptive variable names or add a comment explaining what the variable represents. Of course you can make exceptions for conventional names like x, y, dt, etcetera.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I specified the comments. Please let me know if it's better. Thanks!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not immediately clear what tfwt represents, especially if your are not fluent in numpy conventions.
I'd like better names or comments explaining the computations and intension, please.

tfwt = tfwt[tfwt].index.tolist()

if dup_self:
# subset of prior matrix whose columns are not all zeros (snz: sum non-zero)
prior_snz = self.prior[tfwt]
duplicates = prior_snz.transpose().duplicated(keep=False) # mark duplicates as true
dTFs = duplicates[duplicates].index.tolist()

# find non-duplicated TFs that are also present in target gene list
ndTFs = list(set(self.prior.columns.values.tolist()).difference(dTFs))

if noself:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Ren!
Some minor style nits: variable names should avoid capital letters, e.g. dTFs, and use underscores where appropriate (noself -> no_self).

Echoing @AaronWatters above, one convention that Hammer Lab uses is to avoid abbreviations wherever possible. While this makes the coding a little more verbose, the result is far more readable. E.g. dTFs -> duplicate_tfs, ndTFs -> non_duplicated_tfs, no_self -> no_self_interaction.

selfTFs = list(set(ndTFs).intersection(self.prior.index.values.tolist()))
prior.loc[selfTFs, selfTFs] = 0

activity = pd.DataFrame(0, index = self.prior.columns, columns = self.exp_mat_halftau.columns)

if any(tfwt):
activity.loc[tfwt,:] = np.matrix(linalg.pinv2(prior_snz))* np.matrix(self.exp_mat_halftau)

ntfwt = list(set(self.prior.columns.values.tolist()).difference(tfwt))
activity.loc[ntfwt,:] = exp_mat.loc[ntfwt,:]

return activity