Markov Affinity-based Graph Imputation of Cells (MAGIC) is an algorithm for denoising and transcript recover of single cells applied to single-cell RNA sequencing data, as described in Van Dijk D et al. (2018), Recovering Gene Interactions from Single-Cell Data Using Data Diffusion, Cell https://www.cell.com/cell/abstract/S0092-8674(18)30724-4.
This tutorial shows loading, preprocessing, MAGIC imputation and visualization of myeloid and erythroid cells in mouse bone marrow. You can edit it yourself at https://colab.research.google.com/github/KrishnaswamyLab/MAGIC/blob/master/python/tutorial_notebooks/emt_tutorial.ipynb
If you haven't yet installed MAGIC, we can install it directly from this Jupyter Notebook.
!pip install --user git+git://github.com/KrishnaswamyLab/MAGIC.git#subdirectory=python
Collecting git+git://github.com/KrishnaswamyLab/MAGIC.git#subdirectory=python Cloning git://github.com/KrishnaswamyLab/MAGIC.git to /tmp/pip-req-build-rsiw3uia Requirement already satisfied: numpy>=1.14.0 in /usr/lib/python3.6/site-packages (from magic==1.0.0) (1.14.3) Requirement already satisfied: pandas>=0.21.0 in /usr/lib/python3.6/site-packages (from magic==1.0.0) (0.23.1) Requirement already satisfied: scipy>=1.1.0 in /usr/lib/python3.6/site-packages (from magic==1.0.0) (1.1.0) Requirement already satisfied: matplotlib in /usr/lib/python3.6/site-packages (from magic==1.0.0) (2.2.2) Requirement already satisfied: scikit-learn>=0.19.1 in /usr/lib/python3.6/site-packages (from magic==1.0.0) (0.19.1) Requirement already satisfied: graphtools>=0.1.8 in /old/home/dager/.local/lib/python3.6/site-packages (from magic==1.0.0) (0.1.8) Requirement already satisfied: python-dateutil>=2.5.0 in /usr/lib/python3.6/site-packages (from pandas>=0.21.0->magic==1.0.0) (2.7.3) Requirement already satisfied: pytz>=2011k in /usr/lib/python3.6/site-packages (from pandas>=0.21.0->magic==1.0.0) (2018.5) Requirement already satisfied: cycler>=0.10 in /usr/lib/python3.6/site-packages (from matplotlib->magic==1.0.0) (0.10.0) Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/lib/python3.6/site-packages (from matplotlib->magic==1.0.0) (2.2.0) Requirement already satisfied: six>=1.10 in /usr/lib/python3.6/site-packages (from matplotlib->magic==1.0.0) (1.11.0) Requirement already satisfied: kiwisolver>=1.0.1 in /usr/lib/python3.6/site-packages (from matplotlib->magic==1.0.0) (1.0.1) Requirement already satisfied: pygsp>=0.5.1 in /old/home/dager/.local/lib/python3.6/site-packages (from graphtools>=0.1.8->magic==1.0.0) (0.5.1) Requirement already satisfied: future in /old/home/dager/.local/lib/python3.6/site-packages (from graphtools>=0.1.8->magic==1.0.0) (0.16.0) Requirement already satisfied: setuptools in /usr/lib/python3.6/site-packages (from kiwisolver>=1.0.1->matplotlib->magic==1.0.0) (39.2.0) Building wheels for collected packages: magic Running setup.py bdist_wheel for magic ... done Stored in directory: /tmp/pip-ephem-wheel-cache-fz42s06z/wheels/8c/34/81/1e929fa29dc80dfe23a343266d8ca3e007d9d3ce6fe899d112 Successfully built magic tensorflow 1.8.0 requires astor>=0.6.0, which is not installed. tensorflow 1.8.0 requires gast>=0.2.0, which is not installed. tensorflow 1.8.0 requires grpcio>=1.8.6, which is not installed. tensorflow 1.8.0 requires termcolor>=1.1.0, which is not installed. scikit-image 0.13.0 requires PyWavelets>=0.4.0, which is not installed. pycuda 2017.1.1 requires pytest>=2, which is not installed. pandas-datareader 0.6.0 requires wrapt, which is not installed. Installing collected packages: magic Successfully installed magic-1.0.0
Here, we'll import MAGIC along with other popular packages that will come in handy.
import magic
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
# Matplotlib command for Jupyter notebooks only
%matplotlib inline
Load your data using one of the following magic.io
methods: load_csv
,load_tsv
,load_fcs
,load_mtx
,load_10x
.
You can read about how to use them with help(magic.io.load_csv)
or on https://magic.readthedocs.io/.
emt_data = magic.io.load_csv('../../data/HMLE_TGFb_day_8_10.csv.gz')
emt_data.head()
5_8S_rRNA | A1BG | A1BG-AS1 | A2M | A2M-AS1 | A2ML1 | A2ML1-AS1 | A4GALT | AAAS | AACS | ... | bP-2171C21.6 | chr22-38_28785274-29006793.1 | pk | snoU109 | snoU13 | snoU2-30 | snoU2_19 | snoZ196 | uc_338 | yR211F11.2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
5S_rRNA | |||||||||||||||||||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 rows × 28909 columns
The EMT example data we are using is already pre-filtered and nicely distributed, so we will only demonstrate these preprocessing steps, and not actually perform them on the data. However, these steps are essential for performing MAGIC on single-cell RNA-seq data, so don't skip them if that's what you're working with.
After loading your data, you're going to want to determine the molecule per cell and molecule per gene cutoffs with which to filter the data, in order to remove lowly expressed genes and cells with a small library size.
libsize = emt_data.sum(axis=1)
plt.hist(libsize, bins=50)
plt.axvline(1500, c='r')
plt.show()
if False:
emt_data = emt_data.loc[libsize > 1500]
emt_data.head()
5_8S_rRNA | A1BG | A1BG-AS1 | A2M | A2M-AS1 | A2ML1 | A2ML1-AS1 | A4GALT | AAAS | AACS | ... | bP-2171C21.6 | chr22-38_28785274-29006793.1 | pk | snoU109 | snoU13 | snoU2-30 | snoU2_19 | snoZ196 | uc_338 | yR211F11.2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
5S_rRNA | |||||||||||||||||||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 rows × 28909 columns
After filtering, the next steps are to perform library size normalization and transformation. Log transformation is frequently used for single-cell RNA-seq, however, this requires the addition of a pseudocount to avoid infinite values at zero. We instead use a square root transform, which has similar properties to the log transform but has no problem with zeros.
emt_data = magic.preprocessing.library_size_normalize(emt_data)
if False:
emt_data = np.sqrt(emt_data_norm)
emt_data.head()
5_8S_rRNA | A1BG | A1BG-AS1 | A2M | A2M-AS1 | A2ML1 | A2ML1-AS1 | A4GALT | AAAS | AACS | ... | bP-2171C21.6 | chr22-38_28785274-29006793.1 | pk | snoU109 | snoU13 | snoU2-30 | snoU2_19 | snoZ196 | uc_338 | yR211F11.2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
5S_rRNA | |||||||||||||||||||||
0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.002377 | ... | 0.0 | 0.000000 | 0.00000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | ... | 0.0 | 0.000000 | 1.34385 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | ... | 0.0 | 1.320702 | 0.00000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | ... | 0.0 | 0.000000 | 0.00000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | ... | 0.0 | 0.000000 | 0.00000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
5 rows × 28909 columns
magic_op = magic.MAGIC()
The magic_op.fit_transform function takes the normalized data and an array of selected genes as its arguments. If no genes are provided, MAGIC will return a matrix of all genes. The same can be achieved by substituting the array of gene names with genes='all_genes'
.
emt_magic = magic_op.fit_transform(emt_data, genes=['VIM', 'CDH1', 'ZEB1'])
Calculating MAGIC... Calculating graph and diffusion operator... Calculating PCA... Calculated PCA in 11.78 seconds. Calculating KNN search... Calculated KNN search in 7.04 seconds. Calculating affinities... Calculated affinities in 0.90 seconds. Calculated graph and diffusion operator in 21.25 seconds. Calculating imputation... Automatically selected t = 7 Calculated imputation in 1.25 seconds. Calculated MAGIC in 28.30 seconds.
We can see gene-gene relationships much more clearly after applying MAGIC.
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(16, 6))
points1 = ax1.scatter(emt_data['VIM'], emt_data['CDH1'], c=emt_data['ZEB1'], cmap='inferno', s=1)
ax1.set_xlabel('VIM')
ax1.set_ylabel('CDH1')
ax1.set_title('Before MAGIC')
points2 = ax2.scatter(emt_magic['VIM'], emt_magic['CDH1'], c=emt_magic['ZEB1'], cmap='inferno', s=1)
ax2.set_xlabel('VIM')
ax2.set_ylabel('CDH1')
ax2.set_title('After MAGIC')
plt.colorbar(points1, label='ZEB1')
plt.tight_layout()
plt.show()
The original data suffers from dropout to the point that we cannot infer anything about the gene-gene relationships. As you can see, the gene-gene relationships are much clearer after MAGIC. These relationships also match the biological progression we expect to see in EMT data.
If you did not specify any parameters for your MAGIC operator, you change do so without going through the hassle of creating a new one using the magic_op.set_params method. Since our example EMT dataset is rather large, we can set k=15
, rather than the default k=10
.
magic_op.set_params(k=15)
MAGIC(a=15, k=15, knn_dist='euclidean', n_jobs=1, n_pca=100, random_state=None, t='auto', verbose=1)
We can now run MAGIC on the data again with the new parameters. Given that we have already fitted our MAGIC operator to the data, we should run the magic_op.transform method.
emt_magic = magic_op.transform(genes=['VIM', 'CDH1', 'ZEB1'])
emt_magic.head()
Calculating graph and diffusion operator... Calculating PCA... Calculated PCA in 10.70 seconds. Calculating KNN search... Calculated KNN search in 6.99 seconds. Calculating affinities... Calculated affinities in 0.54 seconds. Calculated graph and diffusion operator in 19.54 seconds. Calculating imputation... Automatically selected t = 7 Calculated imputation in 1.49 seconds.
CDH1 | VIM | ZEB1 | |
---|---|---|---|
5S_rRNA | |||
0 | 0.470840 | 18.768920 | 0.020094 |
0 | 0.452545 | 17.342712 | 0.020327 |
0 | 0.450335 | 20.126832 | 0.024562 |
0 | 0.586670 | 14.195153 | 0.014579 |
0 | 0.441815 | 19.200228 | 0.021331 |
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(16, 6))
points1 = ax1.scatter(emt_data['VIM'], emt_data['CDH1'], c=emt_data['ZEB1'], cmap='inferno', s=1)
ax1.set_xlabel('VIM')
ax1.set_ylabel('CDH1')
ax1.set_title('Before MAGIC')
points2 = ax2.scatter(emt_magic['VIM'], emt_magic['CDH1'], c=emt_magic['ZEB1'], cmap='inferno', s=1)
ax2.set_xlabel('VIM')
ax2.set_ylabel('CDH1')
ax2.set_title('After MAGIC')
plt.colorbar(points2, label='ZEB1')
plt.tight_layout()
plt.show()
We can extract the principal components of the smoothed data by passing the keyword genes='pca_only'
and use this for visualizing the data.
emt_magic_pca = magic_op.transform(genes='pca_only')
emt_magic_pca.head()
PC1 | PC2 | PC3 | PC4 | PC5 | PC6 | PC7 | PC8 | PC9 | PC10 | ... | PC91 | PC92 | PC93 | PC94 | PC95 | PC96 | PC97 | PC98 | PC99 | PC100 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
5S_rRNA | |||||||||||||||||||||
0 | -0.442736 | -12.775098 | -4.966400 | -6.013094 | -3.935735 | -1.701344 | -0.393281 | -0.268059 | 0.406253 | -0.054690 | ... | -0.027859 | -0.005808 | -0.037856 | 0.021984 | -0.079401 | -0.022226 | 0.132161 | 0.002382 | 0.016514 | 0.016606 |
0 | 1.390609 | 20.902626 | -29.119468 | 4.943013 | -0.355160 | 1.257052 | 0.234222 | 0.398224 | 0.902390 | -1.375229 | ... | -0.075673 | 0.029491 | -0.046063 | -0.057150 | -0.021239 | 0.061170 | 0.075315 | -0.063421 | 0.091907 | 0.090922 |
0 | -7.669914 | -22.456203 | -1.263977 | -5.836555 | -3.470875 | -2.354327 | -0.103232 | -0.675641 | -0.139599 | 0.379178 | ... | -0.002656 | -0.033608 | -0.033250 | 0.067121 | -0.082855 | -0.034357 | 0.107429 | -0.017970 | -0.016552 | -0.000571 |
0 | -38.678416 | 48.573566 | 4.139594 | 2.379985 | -0.737370 | 0.667385 | 1.034789 | 0.703243 | -1.325044 | -0.424376 | ... | 0.121966 | 0.087281 | 0.048118 | -0.061236 | 0.003436 | 0.042834 | -0.024626 | 0.027015 | 0.022872 | -0.021877 |
0 | -6.668670 | -14.098860 | -11.448382 | -5.098441 | -3.353138 | -1.019830 | 0.003051 | 0.104561 | 0.102693 | -0.468140 | ... | -0.021234 | -0.044628 | -0.068291 | 0.036636 | -0.057767 | -0.045748 | 0.097285 | -0.025363 | 0.006584 | 0.024934 |
5 rows × 100 columns
from sklearn.decomposition import PCA
emt_pca = PCA(n_components=3).fit_transform(np.array(emt_data))
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(16, 6))
points1 = ax1.scatter(emt_pca[:,0], emt_pca[:,1], c=emt_magic['VIM'], cmap='inferno', s=1)
ax1.set_xlabel('PC1')
ax1.set_ylabel('PC2')
ax1.set_title('PCA without MAGIC')
points2 = ax2.scatter(emt_magic_pca['PC1'], emt_magic_pca['PC2'], c=emt_magic['VIM'], cmap='inferno', s=1)
ax2.set_xlabel('PC1')
ax2.set_ylabel('PC2')
ax2.set_title('PCA with MAGIC')
plt.colorbar(points2, label='VIM')
plt.tight_layout()
plt.show()
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(16,6))
ax1 = fig.add_subplot(121, projection='3d')
points1 = ax1.scatter(emt_pca[:,0], emt_pca[:,1], emt_pca[:,2],
c=emt_magic['VIM'], cmap='inferno', s=1)
ax1.set_xlabel('PC1')
ax1.set_ylabel('PC2')
ax1.set_zlabel('PC3')
ax1.set_title('PCA without MAGIC')
ax2 = fig.add_subplot(122, projection='3d')
points2 = ax2.scatter(emt_magic_pca['PC1'], emt_magic_pca['PC2'], emt_magic_pca['PC3'],
c=emt_magic['VIM'], cmap='inferno', s=1)
ax2.set_xlabel('PC1')
ax2.set_ylabel('PC2')
ax2.set_zlabel('PC3')
ax2.set_title('PCA with MAGIC')
plt.colorbar(points2, label='VIM')
plt.tight_layout()
plt.show()
In complex systems, two dimensions of PCA are not sufficient to view the entire space. For this, PHATE is a suitable visualization tool which works hand in hand with MAGIC to view how gene expression evolves along a trajectory. For this, you will need to have installed PHATE. For help using PHATE, visit https://phate.readthedocs.io/.
!pip install --user phate
Collecting phate Downloading https://files.pythonhosted.org/packages/14/22/bd12cb776ea5ef85369da984c7af6fd4e9a3986b89948cb3a48830c65dad/phate-0.2.8.4.tar.gz Requirement already satisfied: numpy>=1.14.0 in /usr/lib/python3.6/site-packages (from phate) (1.14.3) Requirement already satisfied: pandas>=0.21.0 in /usr/lib/python3.6/site-packages (from phate) (0.23.1) Requirement already satisfied: scipy>=1.1.0 in /usr/lib/python3.6/site-packages (from phate) (1.1.0) Requirement already satisfied: matplotlib>=2.0.1 in /usr/lib/python3.6/site-packages (from phate) (2.2.2) Requirement already satisfied: scikit-learn>=0.19.1 in /usr/lib/python3.6/site-packages (from phate) (0.19.1) Requirement already satisfied: future in /old/home/dager/.local/lib/python3.6/site-packages (from phate) (0.16.0) Requirement already satisfied: graphtools>=0.1.7 in /old/home/dager/.local/lib/python3.6/site-packages (from phate) (0.1.8) Requirement already satisfied: python-dateutil>=2.5.0 in /usr/lib/python3.6/site-packages (from pandas>=0.21.0->phate) (2.7.3) Requirement already satisfied: pytz>=2011k in /usr/lib/python3.6/site-packages (from pandas>=0.21.0->phate) (2018.5) Requirement already satisfied: cycler>=0.10 in /usr/lib/python3.6/site-packages (from matplotlib>=2.0.1->phate) (0.10.0) Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/lib/python3.6/site-packages (from matplotlib>=2.0.1->phate) (2.2.0) Requirement already satisfied: six>=1.10 in /usr/lib/python3.6/site-packages (from matplotlib>=2.0.1->phate) (1.11.0) Requirement already satisfied: kiwisolver>=1.0.1 in /usr/lib/python3.6/site-packages (from matplotlib>=2.0.1->phate) (1.0.1) Requirement already satisfied: pygsp>=0.5.1 in /old/home/dager/.local/lib/python3.6/site-packages (from graphtools>=0.1.7->phate) (0.5.1) Requirement already satisfied: setuptools in /usr/lib/python3.6/site-packages (from kiwisolver>=1.0.1->matplotlib>=2.0.1->phate) (39.2.0) Building wheels for collected packages: phate Running setup.py bdist_wheel for phate ... done Stored in directory: /home/dager/.cache/pip/wheels/74/68/4c/6d8b0047d02390ae00f50de1dca31ca21174be4b38d25b683c Successfully built phate tensorflow 1.8.0 requires astor>=0.6.0, which is not installed. tensorflow 1.8.0 requires gast>=0.2.0, which is not installed. tensorflow 1.8.0 requires grpcio>=1.8.6, which is not installed. tensorflow 1.8.0 requires termcolor>=1.1.0, which is not installed. scikit-image 0.13.0 requires PyWavelets>=0.4.0, which is not installed. pycuda 2017.1.1 requires pytest>=2, which is not installed. pandas-datareader 0.6.0 requires wrapt, which is not installed. Installing collected packages: phate Successfully installed phate-0.2.8.4
import phate
data_phate = phate.PHATE(k=15, a=15).fit_transform(emt_data)
Calculating PHATE... Calculating graph and diffusion operator... Calculating PCA... Calculated PCA in 10.19 seconds. Calculating KNN search... Calculated KNN search in 6.89 seconds. Calculating affinities... Calculated affinities in 0.54 seconds. Calculated graph and diffusion operator in 19.07 seconds. Calculating landmark operator... Calculating SVD... Calculated SVD in 3.67 seconds. Calculating KMeans... Calculated KMeans in 17.66 seconds. Calculated landmark operator in 23.13 seconds. Calculating optimal t... Calculated optimal t in 21.69 seconds. Automatically selected t = 29 Calculating diffusion potential... Calculated diffusion potential in 0.68 seconds. Calculating metric MDS... Calculated metric MDS in 35.81 seconds. Calculated PHATE in 100.40 seconds.
phate.plot.scatter2d(data_phate, c=emt_magic['VIM'], figsize=(12,9))
Finally, if you wish to use the full smoothed matrix in any downstream analysis, you can extract it with the keyword genes="all_genes"
. Note that this matrix may be very large.
emt_magic = magic_op.transform(genes="all_genes")
emt_magic.head()
5_8S_rRNA | A1BG | A1BG-AS1 | A2M | A2M-AS1 | A2ML1 | A2ML1-AS1 | A4GALT | AAAS | AACS | ... | bP-2171C21.6 | chr22-38_28785274-29006793.1 | pk | snoU109 | snoU13 | snoU2-30 | snoU2_19 | snoZ196 | uc_338 | yR211F11.2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
5S_rRNA | |||||||||||||||||||||
0 | 0.000268 | 0.001872 | 0.028677 | 0.000066 | -0.000002 | 0.008798 | -0.000027 | 0.012401 | 0.127582 | 0.220276 | ... | 0.000102 | 0.244597 | 1.186667 | 0.001656 | 0.004390 | 0.000438 | 0.001343 | 0.000233 | 0.021397 | 0.000100 |
0 | 0.000191 | 0.001136 | 0.032752 | 0.000089 | 0.000142 | 0.010621 | 0.000037 | 0.006106 | 0.126881 | 0.216288 | ... | -0.000041 | 0.237189 | 1.166234 | 0.000477 | 0.004618 | 0.000190 | 0.001491 | -0.000059 | 0.015732 | -0.000106 |
0 | 0.000249 | 0.002114 | 0.026938 | 0.000054 | -0.000034 | 0.008515 | -0.000019 | 0.013400 | 0.127766 | 0.220840 | ... | 0.000181 | 0.242696 | 1.187458 | 0.001921 | 0.004160 | 0.000456 | 0.001315 | 0.000287 | 0.022830 | 0.000122 |
0 | -0.000068 | 0.003063 | 0.033745 | 0.000099 | 0.000477 | 0.019462 | 0.000236 | 0.017406 | 0.105561 | 0.232602 | ... | 0.000216 | 0.216487 | 1.157581 | 0.000599 | 0.004030 | 0.000312 | 0.001397 | 0.000006 | 0.012409 | 0.000276 |
0 | 0.000252 | 0.001726 | 0.027796 | 0.000049 | -0.000021 | 0.007596 | -0.000028 | 0.010562 | 0.130447 | 0.219588 | ... | 0.000114 | 0.241396 | 1.177227 | 0.001586 | 0.004302 | 0.000404 | 0.001455 | 0.000230 | 0.021483 | 0.000095 |
5 rows × 28909 columns