Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Monday, June 20, 2016

tensorflow로 logistic regression 구현하기


아래 내용은 Andrew Ng 의 [coursera](https://www.coursera.org/learn/machine-learning/) 강의 일부와 Fast campus 의 [deep learning](http://www.fastcampus.co.kr/data_camp_deeplearning/) 강의 예제와 내용을 이용한 것이다. Andrew Ng 강의에서의 sigmoid function은 코드에서는 softmax function으로 변경되었고 cost function 역시 코드에서는 cross entropy가 사용되었다.

nbviewer  에서도 아래 내용을 볼 수 있다.


Logistic regression

linear regression은 값에 대한 예상치를 구하는 것에 반해 logistic regression은 classification(분류)을 위한 확률 모델이다 (classification 대신 regression을 쓰는 이유는 단지 역사적인 이유일뿐).
아래 식과 같이 input 값 x vector의 weight를 곱한 다항식을 sigmoid function을 통해서 확률값으로 변경한 것이 logistic regression 에 의한 결과이다.
$$ \begin{align} h_\theta &= g(\theta^Tx) &&\text{hypothesis function} \\ g(x) &= {1 \over 1+e^{-x}} &&\text{sigmoid function (=logistic functon)} \\ \end{align} $$
logistic function의 parameter인 theta값은 아래 overall cost function을 이용하여 구한다.
$$ \begin{align} J(\theta) &= {1 \over m} \sum_{i=1}^m Cost(\ h_\theta(x^{(i)}),\ y^{(i)}) &&\text{overall cost function} \\ Cost(h_\theta(x), y) &= \begin{cases} -log(h_\theta(x)), & \mbox{if }y=1 \\ -log(1-h_\theta(x)), & \mbox{if }y=0 \end{cases} &&\text{cost function}\\ &= -ylog(h_\theta(x)) -(1-y)log(1-h_\theta(x)) \\ \end{align} $$
training 데이터의 overall cost function의 최소값이 되도록 하는 theta값이 logistic regression의 parameter가 된다.
$$ min_\theta J(\theta) $$
overall cost function의 최소값이 되는 theta는 아래 gradient descent 를 이용하여 계산한다.
$$ \begin{align} \theta_j &:= \theta_j - \alpha{\partial\over\partial \theta_j}J(\theta) &&\text{gradient descent} \\ &:= \theta_j -\alpha\sum_{i=1}^m(h_\theta(x^{(i)})-y^{(i)})x_j^{(i)} \end{align} $$
위의 gradient descent 식에 training 데이터를 넣어 theta값을 갱신한다. 갱신된 theta를 이용한 overall cost function 값이 더이상 작아지지 않을 때까지 위를 반복한다 (혹은 derivative 가 0에 가까워지면).

Tensorflow

tensorflow는 구글에서 개발한 deep learning 프로그래밍을 위한 python package이다.
tensorflow를 이용하는 것은 deep learning을 위한 graph(=model)를 구축한는 것이라고 생각하면 될 것 같다. 그래프의 입력값과 같은 데이터의 통로는 tensorflow의 placeholder 라는 것으로 정의하고 데이터를 사용하여 그래프가 트레이닝 되는 동안 변해가는 값, 곧 변수는 tensorflow의 Variable을 사용하여 정의한다. 그래프를 구축하고 실제로 그 그래프를 실행하는 것은 tensorflow 의 session의 run을 사용한다.
In [19]:
%matplotlib inline    # maplotlib의 그림을 notebook 안에 그리기 위한 명령어 (magic이라 함)

import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
In [32]:
mnist = input_data.read_data_sets('data/', one_hot=True)
Extracting data/train-images-idx3-ubyte.gz
Extracting data/train-labels-idx1-ubyte.gz
Extracting data/t10k-images-idx3-ubyte.gz
Extracting data/t10k-labels-idx1-ubyte.gz
In [34]:
print mnist.train.num_examples
55000
notebook 이 실행된 폴더의 서브폴더 data를 생성하고 그 안에 mnist 데이터를 다운받게 된다. mnist는 Mixed National Institute of Standards and Technology의 약어로 이미지 프로세싱 시스템을 트레이닝에 사용되는 손글씨로 쓴 숫자 이미지의 모음이다. one_hot 인자의 true의 의미는 숫자의 label 을 0과 1로 표현하겠다는 의미이다.
In [33]:
trainimg = mnist.train.images 
trainlabel = mnist.train.labels 
testimg = mnist.test.images
testlabel = mnist.test.labels

print type(trainimg), type(trainlabel)
print trainimg.shape, trainlabel.shape
print type(trainimg[0]), trainimg[0].shape
print type(trainlabel[0]), trainlabel[0].shape
print trainlabel[10]
plt.imshow(trainimg[10].reshape((28,28)))
<type 'numpy.ndarray'> <type 'numpy.ndarray'>
(55000, 784) (55000, 10)
<type 'numpy.ndarray'> (784,)
<type 'numpy.ndarray'> (10,)
[ 1.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
Out[33]:
<matplotlib.image.AxesImage at 0x10c624a90>
trainimg 는 55000 행과 784 열로 이루어진 2-dimensional array 이다. 행은 training할 데이터의 수를 의미하며 열은 하나의 데이터를 이루는 숫자의 모음이다. 곧 트레이닝 데이터는 55000개로 이루어 져 있으며 하나의 데이터는 784 (=28*28)의 숫자로 구성되어 있다. trainlabel 역시 2차원 array이며 각 행은 각 데이터의 label을 의미하며 각 데어터의 label은 10개의 0혹은 1 값으로 구성되어 있다.
위의 예처럼 그림이 0을 의미하면 label의 값 중에 0 을 의미하는 첫번째 인덱스의 값만 1이고 나머지는 0이 된다.
In [40]:
learning_rate = 0.01
training_epochs = 50
batch_size = 100
display_step = 10

x = tf.placeholder('float', [None, 784])  # trainimg 혹은 testimg가 들어갈 변수, 데이터가 들어갈 입력변수
y = tf.placeholder('float', [None, 10])  # None 은 입력 데이터의 행 수를 임의로 지정한 것
W = tf.Variable(tf.zeros([784, 10]))  # 그래프가 트레이닝 됨에 따라 변하는 변수
b = tf.Variable(tf.zeros([10]))  # bias 를 나타나내는 변수

actv = tf.nn.softmax(tf.matmul(x, W) + b)
cost = tf.reduce_mean(-tf.reduce_sum(y * tf.log(actv), reduction_indices=1)) # cross entropy
#cost = tf.reduce_mean(tf.pow(actv - y, 2))  # squared loss

optm = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

pred = tf.equal(tf.argmax(actv, 1), tf.argmax(y, 1))
accr = tf.reduce_mean(tf.cast(pred, 'float'))

init = tf.initialize_all_variables()
epoch 는 모든 training data가 다 사용되는 한번의 turn(=loop)을 뜻하며 batch size는 한번의 turn(=loop)이 되는 동안 사용되어 지는 데이터의 크기(=갯수)를 뜻한다. 예를 들어 55000개의 training data가 있을 경우 batch size 를 100으로 정했으면 550 번의 iteration이 돌아야 한번의 epoch가 완성되는 것이다.
위 코드에서는 sigmoid function 대신 softmax function을 사용하였다.
$$ softmax_i(a) = { e^{a_i} \over \sum e^{a_i}} \ \ \ \ \ \ \ \ \text{softmax} $$
또한 cost function으로 cross entropy 를 사용하였다.
$$ H(p, q) = -\sum_x p(x)\ log\ q(x) \ \ \ \ \ \ \ \ \text{cross entropy} $$
In [42]:
with tf.Session() as sess: # 위의 코드는 그래프를 생성한 것. 실제로 구동은 Session에서 이뤄진다
    sess.run(init)
    
    for epoch in range(training_epochs):
        avg_cost = 0.
        num_batch = int(mnist.train.num_examples / batch_size)
        for i in range(num_batch):
            if 0: # tensorflow 에서 제공하는 mnist데이터 객체의 batch 를 뽑아내는 함수를 이용하는 방법  
                batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            else: # OR manually implement random extraction
                randidx = np.random.randint(trainimg.shape[0], size = batch_size)
                batch_xs = trainimg[randidx, :]
                batch_ys = trainlabel[randidx, :]
                
            sess.run(optm, feed_dict = {x: batch_xs, y: batch_ys}) # optimizer 를 실행. placeholder로 잡아논 변수를 인자로 넣어줌.
            avg_cost += sess.run(cost, feed_dict = {x: batch_xs, y: batch_ys}) / num_batch
        
        if epoch % display_step == 0:
            train_acc = accr.eval({x: batch_xs, y: batch_ys})
            print "Epoch: %03d/%03d cost: %.9f train_acc: %.3f"%(epoch, training_epochs, avg_cost, train_acc)
            
    print "Optimizer finished."
    print "Accuracy:", accr.eval({x: mnist.test.images, y: mnist.test.labels})

print "Done."
Epoch: 000/050 cost: 1.172424991 train_acc: 0.890
Epoch: 010/050 cost: 0.382650341 train_acc: 0.920
Epoch: 020/050 cost: 0.340528482 train_acc: 0.940
Epoch: 030/050 cost: 0.325556715 train_acc: 0.940
Epoch: 040/050 cost: 0.309887736 train_acc: 0.880
Optimizer finished.
Accuracy: 0.9183
Done.

Tuesday, January 20, 2015

ipython notebook to pdf

1. ipython nbconvert sample.ipynb --to latex --post PDF
trouble: 에러 발생 (원인 불명)

2. ipython nbconvert sample.ipynb --to latex 후 pdflatex sample.tex
trouble : 한글의 경우 utf-8 인대도 에러 발생

3. brew install Caskroom/cask/wkhtmltopdf  깔고
ipython nbconvert sample.ipynb --to html 후 wkhtmltopdf sample.html sample.pdf
trouble :  plot이 page 넘어가는 부분에 있을 경우 plot이 쪼개짐

Wednesday, January 14, 2015

SNP chip analysis (from raw data to phylogenetic tree)


아래 과정은 snp chip에서 case-control GWAS study까지의 대략적인 코드이다.


Parse raw file

describe parsing script.
In [1]:
#parse raw file

import csv

handle = open("snp_chips.csv")
reader = csv.reader(handle)
replicate = 4
start_column = -16 * replicate + replicate - 1
samples = reader.next()[start_column : : replicate]
samples = ['snp_id'] + [sample.split('.')[0] for sample in samples]
print 'samples      ::', samples
print 'sample count ::', len(samples) - 1


str_output_ori = '{}\n'.format(','.join(samples))
str_output_val = str_output_ori
str_output_val_filtered = str_output_val
str_output_ori = 'chr,pos,' + str_output_ori
pure_row_count = 0
for sp in reader:
    if sp[0][0] == '#':
        continue
    snps = [sp[1]] + sp[start_column :: replicate]
    str_snps = ','.join(snps)
    str_output_ori += '{0},{1},{2}\n'.format(int(sp[53][-2:]),
                                             sp[56], str_snps)
    str_snps = str_snps.replace("AAAA","0")
    str_snps = str_snps.replace("AAAC","1")
    str_snps = str_snps.replace("AACC","2")
    str_snps = str_snps.replace("ACCC","3")
    str_snps = str_snps.replace("CCCC","4")
    
    str_snps = str_snps.replace("AAAG","1")
    str_snps = str_snps.replace("AAGG","2")
    str_snps = str_snps.replace("AGGG","3")
    str_snps = str_snps.replace("GGGG","4")
    
    str_snps = str_snps.replace("TTTT","0")
    str_snps = str_snps.replace("TTTC","1")
    str_snps = str_snps.replace("TTCC","2")
    str_snps = str_snps.replace("TCCC","3")
    str_snps = str_snps.replace("CCCC","4")
    
    str_snps = str_snps.replace("TTTG","1")
    str_snps = str_snps.replace("TTGG","2")
    str_snps = str_snps.replace("TGGG","3")
    str_snps = str_snps.replace("GGGG","4")
    
    str_snps = str_snps.replace("X","nan")
    str_snps = str_snps.replace("NC","nan")
    str_output_val += '{}\n'.format(str_snps)
    if 'nan' not in str_snps:
        pure_row_count += 1
        str_output_val_filtered += '{}\n'.format(str_snps)

#print 'snps which all samples have value :: ', pure_row_count

handle.close()

handle_w = open('snp_chips.parsed.csv','w')
handle_w.write(str_output_ori)
handle_w.close()
handle_w = open('snp_chips.parsed.value.csv','w')
handle_w.write(str_output_val)
handle_w.close()
handle_w = open('snp_chips.parsed.value.filterd.csv','w')
handle_w.write(str_output_val_filtered)
handle_w.close()
samples      :: ['snp_id', 'sample1', 'sample2', 'sample9', 'sample3', 'sample5', 'sample14', 'sample13', 'sample11', 'sample16', 'sample12', 'sample15', 'sample6', 'sample8', 'sample7', 'sample4', 'sample10']
sample count :: 16

SNP simple stats

In [2]:
#SNP simple stats

import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv('snp_chips.parsed.value.csv', index_col=0)
## hist duplicated probes
duplicated_snps = []
indexes = list(data.index)
for snp in indexes:
    duplicated_count = indexes.count(snp)
    if duplicated_count > 1:
        duplicated_snps.append(snp)
print "duplicate probes :: ", len(set(duplicated_snps))

data["index"] = data.index
data.drop_duplicates(cols='index', take_last=True, inplace=True) # remove
                                                        # duplicate row
del data["index"]

## plot non-nan count of samples
snp_count_per_sample = data.apply(lambda x: sum(x.notnull()))
fig, ax = plt.subplots(figsize=(15,4))
ax.plot(snp_count_per_sample, marker='o', ls='-', color='blue')
ax.set_xticks(range(0,16))
ax.set_xticklabels(snp_count_per_sample.index, rotation=-45)
ax.set_xlim([-1,16])
ax.grid(True)
ax.set_title('# of SNPs with value per sample')
ax.set_xlabel('sample names')
ax.set_ylabel('# of SNPs with value')
for i in range(len(snp_count_per_sample.index)):
    ax.text(i, snp_count_per_sample[i], snp_count_per_sample[i], 
            ha='center', va='bottom')
duplicate probes ::  455

In [3]:
data = data.loc[data.apply(lambda x: sum(x.isnull()),axis=1) == 0,:]
print 'filtered data ::', data.shape
filtered data :: (2494, 16)

PCA dimension reduction

In [4]:
#PCA dimension reduction

from sklearn.decomposition import PCA
import math
import numpy as np


pca = PCA(n_components=3)
pca.fit(data.T)
tc = pca.transform(data.T)

colors = cm.rainbow(np.linspace(0, 1, len(tc)))
fig, ax = plt.subplots(figsize=(10,10))
for i, sample in enumerate(data.columns):
    ax.plot(tc[i, 0], tc[i, 1], marker='o', ls='*', color=colors[i])
    ax.text(tc[i, 0], tc[i, 1], sample, ha='left', va='bottom', 
            color=colors[i])
ax.set_title('PCA reduction')
ax.set_xlabel('principle component 1')
ax.set_ylabel('principle component 2')
Out[4]:
<matplotlib.text.Text at 0x107666510>

Phylogenetic tree

  1. Calculate genetic distance

  • Calculate Genetic distance (http://www.plosgenetics.org/article/info%3Adoi%2F10.1371%2Fjournal.pgen.1002451)
    : Genetic distance (D) between pair-wise combinations of individuals was calculated as PLINK where

    \[ D = 1−{(IBS2+0.5 \times IBS1) \over N} \]
    IBS2 and IBS1 are the number of loci that share either 2 or 1 alleles identical by state (IBS), respectively, and N is the number of loci tested.
  • Make distance matrix file (phylip input file)
    : The input format for distance data is straightforward. The first line of the input file contains the number of species. There follows species data, starting, as with all other programs, with a species name. The species name is ten characters long, and must be padded out with blanks if shorter. And every cell should be space delimited.
In [7]:
## calculate genetic distance
import math

distance_file = 'distance_matrix.txt'

def calculate_distance(s1, s2, allele_num):
    return 1 - (allele_num - (s1 - s2).apply(math.fabs)).sum() / (allele_num * len(s1))
distance_matrix = data.apply(lambda x1: data.apply(
                        lambda x2: calculate_distance(x1, x2, 4)))
str_output = '{0}\n'.format(len(distance_matrix))
for sample in distance_matrix.index:
    sample_name = sample[:10] if len(sample) > 10 else sample + ' '*(10-len(sample))
    str_output += '{0} {1}\n'.format(sample_name,
        ' '.join(['{:.4f}'.format(v) for v in distance_matrix.loc[sample,]]))

handle = open(distance_file, 'w')
handle.write(str_output)
handle.close()

  1. Convert distance matrix to newick format

Use Phylip (check "Running the programs in background or under control of a command file" in http://evolution.genetics.washington.edu/phylip/doc/main.html).
In [8]:
import os
from IPython.display import Image

if os.path.isfile('outfile'):
    os.remove('outfile')
if os.path.isfile('outtree'):
    os.remove('outtree')
str_output = '{0}\nY\n'.format(distance_file)
handle = open('fitch_input','w')
handle.write(str_output)
handle.close()
os.system('fitch < fitch_input > fitch_result')
Out[8]:
0

  1. Draw tree

use phylip drawgram, drawtree
In [9]:
## draw tree with python package "ete2"

from ete2 import Tree, TreeStyle

handle = open('outtree')
lines = handle.readlines()
handle.close()
newick = ''.join([line.strip() for line in lines])
t = Tree(newick)
t.show()
#t.render('myTree.png', w=150, h = 150, units='mm')
#Image(filename='myTree.png') 
No module named MySQLdb

 MySQLdb module could not be loaded

In [10]:
## draw tree with phylip "drawtree"
## phylip "drawtree" make ps format file. Converting file format is needed to render image.

loc_fontfile = 'font1' # check the location of fontfile
handle = open('drawtree_input', 'w')
handle.write('outtree\n{0}\nY\n'.format(loc_fontfile)) 
handle.close()
commands = []
commands.append('drawtree < drawtree_input > drawtree_result') # use phylip "drawtree"
commands.append('mv plotfile drawtree.ps')
commands.append('convert drawtree.ps drawtree.png') # use "convert"
for command in commands:
    os.system(command)
Image(filename='drawtree.png')
Out[10]:
In [11]:
# draw tree with phylip "fitch" result

handle = open('outfile')
lines = handle.readlines()
handle.close()
start_index_str = 'Negative branch lengths not allowed\n'
end_index_str = 'remember: this is an unrooted tree!\n'
print '<Unrooted Tree>'
print ''.join(lines[lines.index(start_index_str)+1: 
                                    lines.index(end_index_str)])
<Unrooted Tree>


        +--sample16  
      +-7 
      ! +--sample2   
    +-9 
    ! ! +---sample3   
    ! +-3 
  +-2   !  +--sample4   
  ! !   +-13  
  ! !      +---sample5   
  ! ! 
  ! +----sample6   
  ! 
  !    +-----sample7   
  !    !  
  ! +-12     +---sample8   
  ! !  !  +-11  
  ! !  !  !  +----sample9   
  ! !  +-10  
  ! !     !  +----sample10  
  ! !     !  !  
  ! !     +-14   +---sample11  
  4-1        ! +-6 
  ! !        ! ! ! +---sample12  
  ! !        +-5 +-8 
  ! !          !   +----sample13  
  ! !          ! 
  ! !          +----sample14  
  ! ! 
  ! +----sample15  
  ! 
  +----sample1   




Significant diff SNPs

use plink (consider all of heterozygosity as 1) up to manhattan plot PLINK case-control association test result("assoc") fields summary
CHR     Chromosome
SNP     SNP ID
BP      Physical position (base-pair)
A1      Minor allele name (based on whole sample)
F_A     Frequency of this allele in cases
F_U     Frequency of this allele in controls
A2      Major allele name
CHISQ   Basic allelic test chi-square (1df)
P       Asymptotic p-value for this test
OR      Estimated odds ratio (for A1, i.e. A2 is reference)
In [12]:
# make PLINK input files
group1 = ['sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6']
group2 = ['sample7', 'sample8', 'sample9', 'sample10', 'sample11', 
          'sample12', 'sample13', 'sample14', 'sample15','sample16']

## make MAP file
data_plink = pd.read_csv('snp_chips.parsed.csv', index_col=2)
data_plink = data_plink.loc[data.index,:]
data_plink['id'] = data_plink.index
data_plink.drop_duplicates(cols='id', take_last=True, inplace=True)
data_map = data_plink[['chr', 'id', 'pos']]
data_map.to_csv('data.map', sep=' ', index=False, header=False)

## make PED file
data_plink = data_plink.drop(['chr', 'pos', 'id'], axis=1)
data_ped = data_plink.apply(lambda x: ' '.join('{0} {1}'.format(
                                        snp[0], snp[-1]) for snp in x))
str_output = ''
for sample in data_ped.index:
    str_output += '{0} {1} {2}\n'.format(sample, 1 if sample in group1
                                         else 2, data_ped[sample])
handle = open('data.ped', 'w')
handle.write(str_output)
handle.close()

# execute plink
plink_command = 'plink --file data --assoc --no-fid --no-parents '\
                                '--allow-no-sex --no-sex --map3 --adjust'
os.system(plink_command)
Out[12]:
0
In [13]:
# draw Manhattan plot
import matplotlib.cm as cm

plink_map = pd.read_csv('data.map', header=None, sep=' ', index_col=1)
plink_map.columns = ['chr', 'pos']
handle = open('plink.assoc')
lines = handle.readlines()
handle.close()
plink_pvalue = pd.DataFrame([{'id': line.strip().split()[1], 
            'pvalue':line.strip().split()[8]} for line\
            in lines[1:] if line.strip().split()[8] != 'NA' ])
plink_pvalue.index = plink_pvalue['id']
plink_map = plink_map.loc[plink_pvalue.index, :]
result = pd.concat([plink_map, plink_pvalue], join='outer', axis=1)
chr_x_axis = result.pivot_table(cols='chr', aggfunc='max')
chr_x_axis = chr_x_axis.loc['pos',].cumsum()
x_axis = result.apply(lambda x: (x['pos'] + chr_x_axis[x['chr']-1])\
                      if x['chr'] != 0else x['pos'], axis=1)
y_axis = pd.Series([-math.log(float(x), 10) for x in result['pvalue']])

fig, ax = plt.subplots(figsize=(15,4))

colors = cm.rainbow(np.linspace(0, 1, len(chr_x_axis)))
for i, chr in enumerate(chr_x_axis.index):
    rt = result.loc[result['chr'] == chr, :]
    x_axis = rt.apply(lambda x: (x['pos'] + chr_x_axis[x['chr']-1])\
                      if x['chr'] != 0else x['pos'], axis=1)
    y_axis = pd.Series([-math.log(float(x), 10) for x in rt['pvalue']])
    
    ax.plot(x_axis, y_axis, ls='*', marker='o',color=colors[i])
ax.set_xticks([0] + [i for i in chr_x_axis.values])
ax.set_xticklabels(['chr{}'.format(i) for i in chr_x_axis.index],
                   rotation=-45)
ax.grid(True)
ax.set_title('Manhattan plot')
ax.set_xlabel('chromosome (bp)')
ax.set_ylabel('pvalue (-log10)')
Out[13]:
<matplotlib.text.Text at 0x10a23cdd0>

SNPs diversity

ROD

\[ ROD = 1 - \pi_{cul} / \pi_{wild} \] \[ \pi = \Sigma_{ij}x_ix_j\pi_{ij} = 2* \Sigma_{i=1}^n\Sigma_{j=1}^{i-1}x_ix_j\pi_{ij} \]
where \(x_i\) and \(x_j\) are the respective frequencies of the ith and jth sequences, \(\pi_{ij}\) is the number of nucleotide differences per nucleotide site between the ith and jth sequences, and n is the number of sequences in the sample.
- calculation example : http://www.vcu.edu/csbc/lfsc520/week7/Week7LectureNotes.pdf

selective sweep analysis\({}^1\)

We used allele counts at SNP positions to identify signatures of selection in sliding 40-kb windows, for pools of sequence data. For each pool and SNP, we determined the numbers of reads corresponding to the most and least abundant allele (\(n_{MAJ}\) and \(n_{MIN}\)). For each window in each breed pool, we calculated a pooled heterozygosity score: \(H_p = 2\Sigma n_{MAJ}\Sigma n_{MIN}/ (\Sigma n_{MAJ} + \Sigma n_{MIN}){}^2\), where SnMAJ and SnMIN are the sums of \(n_{MAJ}\) and, respectively, \(n_{MIN}\) for all SNPs in the window. Individual \(H_p\) values were then Z-transformed as follows: \(ZH_p = (H_p - \mu H_p)/ \sigma H_p\). \({}_{1. http://www.nature.com/nature/journal/v464/n7288/abs/nature08832.html}\)
In []: