{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用 PCA 可视化单细胞表达数据\n",
    "\n",
    "在本实验中，您将使用 PCA 可视化来自Guo 等人的一些单细胞基因表达数据。 “从受精卵到囊胚的单细胞基因表达分析揭示细胞命运决定的解决方案”，《发育细胞》，第 18 卷，第 4 期，2010 年 4 月 20 日，第 675-685 页，可从 http://dx.doi.org/10.1016 获取 /j.devcel.2010.02.012。 论文 pdf 版本可在第 4 周的讲义文件夹中找到。\n",
    "\n",
    "数据来自小鼠 qPCR TaqMan 阵列单细胞实验。 数据取自胚泡形成时的早期发育阶段。 在 32 细胞阶段，数据已被分离成滋养外胚层 (TE)，进而形成胎盘和内细胞团 (ICM)。 ICM 进一步分化为外胚层 (EPI)（产生内胚层、中胚层和外胚层）以及发育成羊膜袋的原始内胚层 (PE)。 郭等人选择了48个基因进行表达测量。 他们标记了生成的细胞，并将其标签作为可视化的辅助工具。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Unnamed: 0</th>\n",
       "      <th>Actb</th>\n",
       "      <th>Ahcy</th>\n",
       "      <th>Aqp3</th>\n",
       "      <th>Atp12a</th>\n",
       "      <th>Bmp4</th>\n",
       "      <th>Cdx2</th>\n",
       "      <th>Creb312</th>\n",
       "      <th>Cebpa</th>\n",
       "      <th>Dab2</th>\n",
       "      <th>...</th>\n",
       "      <th>Sox2</th>\n",
       "      <th>Sall4</th>\n",
       "      <th>Sox17</th>\n",
       "      <th>Snail</th>\n",
       "      <th>Sox13</th>\n",
       "      <th>Tcfap2a</th>\n",
       "      <th>Tcfap2c</th>\n",
       "      <th>Tcf23</th>\n",
       "      <th>Utf1</th>\n",
       "      <th>Tspan8</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>-0.541050</td>\n",
       "      <td>1.203007</td>\n",
       "      <td>-1.030746</td>\n",
       "      <td>-1.064808</td>\n",
       "      <td>-0.494782</td>\n",
       "      <td>0.167143</td>\n",
       "      <td>1.369092</td>\n",
       "      <td>-1.083061</td>\n",
       "      <td>-0.668057</td>\n",
       "      <td>...</td>\n",
       "      <td>1.351757</td>\n",
       "      <td>1.793476</td>\n",
       "      <td>-0.783185</td>\n",
       "      <td>1.408063</td>\n",
       "      <td>0.031991</td>\n",
       "      <td>0.351257</td>\n",
       "      <td>1.078982</td>\n",
       "      <td>-0.942981</td>\n",
       "      <td>-1.348892</td>\n",
       "      <td>1.051999</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>-0.680832</td>\n",
       "      <td>1.355306</td>\n",
       "      <td>-2.456375</td>\n",
       "      <td>-1.234350</td>\n",
       "      <td>-0.645494</td>\n",
       "      <td>-1.003868</td>\n",
       "      <td>1.207595</td>\n",
       "      <td>-1.208023</td>\n",
       "      <td>-0.800388</td>\n",
       "      <td>...</td>\n",
       "      <td>1.363533</td>\n",
       "      <td>1.782172</td>\n",
       "      <td>-1.532477</td>\n",
       "      <td>1.361172</td>\n",
       "      <td>0.501715</td>\n",
       "      <td>-1.082362</td>\n",
       "      <td>0.930112</td>\n",
       "      <td>-1.064399</td>\n",
       "      <td>-1.469397</td>\n",
       "      <td>0.996275</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>-1.056038</td>\n",
       "      <td>1.280447</td>\n",
       "      <td>-2.046133</td>\n",
       "      <td>-1.439795</td>\n",
       "      <td>-0.828121</td>\n",
       "      <td>-0.983404</td>\n",
       "      <td>1.460032</td>\n",
       "      <td>-1.359447</td>\n",
       "      <td>-0.530701</td>\n",
       "      <td>...</td>\n",
       "      <td>1.296802</td>\n",
       "      <td>1.567402</td>\n",
       "      <td>-3.194157</td>\n",
       "      <td>1.301777</td>\n",
       "      <td>0.445219</td>\n",
       "      <td>-0.031284</td>\n",
       "      <td>1.005767</td>\n",
       "      <td>-1.211529</td>\n",
       "      <td>-1.615421</td>\n",
       "      <td>0.651393</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>-0.732331</td>\n",
       "      <td>1.326911</td>\n",
       "      <td>-2.464234</td>\n",
       "      <td>-1.244323</td>\n",
       "      <td>-0.654359</td>\n",
       "      <td>-0.947023</td>\n",
       "      <td>1.265609</td>\n",
       "      <td>-1.215373</td>\n",
       "      <td>-0.765212</td>\n",
       "      <td>...</td>\n",
       "      <td>1.684100</td>\n",
       "      <td>1.915556</td>\n",
       "      <td>-2.962515</td>\n",
       "      <td>1.349710</td>\n",
       "      <td>-1.875957</td>\n",
       "      <td>-1.699892</td>\n",
       "      <td>1.059458</td>\n",
       "      <td>-1.071541</td>\n",
       "      <td>-1.476485</td>\n",
       "      <td>0.699586</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>-0.629333</td>\n",
       "      <td>1.244308</td>\n",
       "      <td>-1.316815</td>\n",
       "      <td>-1.304162</td>\n",
       "      <td>-0.707552</td>\n",
       "      <td>-1.429070</td>\n",
       "      <td>0.895578</td>\n",
       "      <td>0.007785</td>\n",
       "      <td>-0.644606</td>\n",
       "      <td>...</td>\n",
       "      <td>1.304653</td>\n",
       "      <td>1.761825</td>\n",
       "      <td>-1.265379</td>\n",
       "      <td>1.320533</td>\n",
       "      <td>0.609864</td>\n",
       "      <td>-0.413826</td>\n",
       "      <td>0.888624</td>\n",
       "      <td>-1.114394</td>\n",
       "      <td>-1.519017</td>\n",
       "      <td>0.798985</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 49 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "  Unnamed: 0      Actb      Ahcy      Aqp3    Atp12a      Bmp4      Cdx2  \\\n",
       "0          1 -0.541050  1.203007 -1.030746 -1.064808 -0.494782  0.167143   \n",
       "1          1 -0.680832  1.355306 -2.456375 -1.234350 -0.645494 -1.003868   \n",
       "2          1 -1.056038  1.280447 -2.046133 -1.439795 -0.828121 -0.983404   \n",
       "3          1 -0.732331  1.326911 -2.464234 -1.244323 -0.654359 -0.947023   \n",
       "4          1 -0.629333  1.244308 -1.316815 -1.304162 -0.707552 -1.429070   \n",
       "\n",
       "    Creb312     Cebpa      Dab2  ...      Sox2     Sall4     Sox17     Snail  \\\n",
       "0  1.369092 -1.083061 -0.668057  ...  1.351757  1.793476 -0.783185  1.408063   \n",
       "1  1.207595 -1.208023 -0.800388  ...  1.363533  1.782172 -1.532477  1.361172   \n",
       "2  1.460032 -1.359447 -0.530701  ...  1.296802  1.567402 -3.194157  1.301777   \n",
       "3  1.265609 -1.215373 -0.765212  ...  1.684100  1.915556 -2.962515  1.349710   \n",
       "4  0.895578  0.007785 -0.644606  ...  1.304653  1.761825 -1.265379  1.320533   \n",
       "\n",
       "      Sox13   Tcfap2a   Tcfap2c     Tcf23      Utf1    Tspan8  \n",
       "0  0.031991  0.351257  1.078982 -0.942981 -1.348892  1.051999  \n",
       "1  0.501715 -1.082362  0.930112 -1.064399 -1.469397  0.996275  \n",
       "2  0.445219 -0.031284  1.005767 -1.211529 -1.615421  0.651393  \n",
       "3 -1.875957 -1.699892  1.059458 -1.071541 -1.476485  0.699586  \n",
       "4  0.609864 -0.413826  0.888624 -1.114394 -1.519017  0.798985  \n",
       "\n",
       "[5 rows x 49 columns]"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "# Load the data\n",
    "data = pd.read_csv('/mnt/d/coding/codes/ML/2022-23/week 4/handout-solutions/GuoData.csv')\n",
    "\n",
    "# Display the first few rows of the dataframe\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用sklearn库中的PCA并可视化数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_1423/1452153998.py:32: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed two minor releases later. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap(obj)`` instead.\n",
      "  colormap = plt.cm.get_cmap('tab10', len(unique_cell_types))\n",
      "/tmp/ipykernel_1423/1452153998.py:37: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored\n",
      "  plt.scatter(subset['PC1'], subset['PC2'], label=str(cell_type), cmap=colormap, color=colormap(idx))\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 112952 characters]",
      "text/plain": [
       "<Figure size 1200x1000 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.decomposition import PCA\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Extract cell labels\n",
    "cell_labels = data['Unnamed: 0']\n",
    "\n",
    "# Dropping the unnamed column\n",
    "data = data.drop(columns=[\"Unnamed: 0\"])\n",
    "\n",
    "# Standardize the feature matrix\n",
    "data_std = StandardScaler().fit_transform(data)\n",
    "\n",
    "# Create a PCA instance: pca\n",
    "pca = PCA(n_components=2)\n",
    "\n",
    "# Fit and transform the standardized data\n",
    "principalComponents = pca.fit_transform(data_std)\n",
    "\n",
    "# Create a dataframe with the first two principal components\n",
    "PCA_df = pd.DataFrame(data = principalComponents, columns = ['PC1', 'PC2'])\n",
    "\n",
    "# Add the cell labels to the PCA dataframe\n",
    "PCA_df['Cell Type'] = cell_labels\n",
    "\n",
    "PCA_df.head()\n",
    "\n",
    "# Checking the unique cell types present in the dataset\n",
    "unique_cell_types = PCA_df['Cell Type'].unique()\n",
    "\n",
    "# Define a colormap to ensure distinct colors\n",
    "colormap = plt.cm.get_cmap('tab10', len(unique_cell_types))\n",
    "\n",
    "plt.figure(figsize=(12,10))\n",
    "for idx, cell_type in enumerate(unique_cell_types):\n",
    "    subset = PCA_df[PCA_df['Cell Type'] == cell_type]\n",
    "    plt.scatter(subset['PC1'], subset['PC2'], label=str(cell_type), cmap=colormap, color=colormap(idx))\n",
    "plt.title('PCA on the Dataset (colored by cell type)')\n",
    "plt.xlabel('Principal Component 1')\n",
    "plt.ylabel('Principal Component 2')\n",
    "plt.legend(title='Cell Type', bbox_to_anchor=(1.05, 1), loc='upper left')\n",
    "plt.grid(True)\n",
    "plt.show()\n",
    "\n",
    " \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 需要多少个主成分（PC）才能解释数据中80%以上的数据？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "11"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "# Create a PCA instance: pca\n",
    "pca = PCA()\n",
    "\n",
    "# Fit the standardized data\n",
    "pca.fit(data_std)\n",
    "\n",
    "# Calculate cumulative sum of explained variances\n",
    "cumulative_variance = np.cumsum(pca.explained_variance_ratio_)\n",
    "\n",
    "# Find the number of components for more than 80% variance\n",
    "num_components = np.where(cumulative_variance > 0.8)[0][0] + 1  # Adding 1 as indexing starts from 0\n",
    "\n",
    "num_components"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 57096 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(12,6))\n",
    "plt.bar(range(1, len(pca.explained_variance_ratio_) + 1), pca.explained_variance_ratio_, alpha=0.5, align='center', label='Individual explained variance')\n",
    "plt.step(range(1, len(cumulative_variance) + 1), cumulative_variance, where='mid', label='Cumulative explained variance')\n",
    "plt.axhline(y=0.8, color='r', linestyle='--', label='80% explained variance')\n",
    "plt.axvline(x=num_components, color='g', linestyle='--', label='Number of components for 80% variance')\n",
    "plt.ylabel('Explained Variance Ratio')\n",
    "plt.xlabel('Principal Components')\n",
    "plt.legend(loc='best')\n",
    "plt.title('Explained Variance by Different Principal Components')\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在上图中：\n",
    "\n",
    "蓝色条代表每个主成分解释的方差。\n",
    "\n",
    "橙色线代表累积解释方差。\n",
    "\n",
    "红色虚线标记解释方差的 80% 水平。\n",
    "\n",
    "绿色虚线表示达到 80% 阈值所需的主成分数量（11 个成分）。\n",
    "\n",
    "正如您所看到的，前几个主成分贡献了总方差的很大一部分，而后面的成分解释了较小的方差。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 您认为哪种 PC 对于区分 TE 单元类型（32TE 和 64TE）与其他单元最有用？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 PCA 图中，主成分 1 (PC1) 和主成分 2 (PC2) 都有助于分离不同细胞类型，包括 TE 细胞类型（32TE 和 64TE）。\n",
    "\n",
    "从散点图来看，似乎：\n",
    "\n",
    "PC1 将 32TE 和 64TE 与大多数其他细胞类型清楚地区分开来，尤其是与位于图右侧的细胞类型（细胞类型“4”、“8”、“16”和“32 ICM”）区分开来。\n",
    "\n",
    "PC2 也有助于区分，但与 PC1 相比，程度较小。它在图的顶部提供了 64TE 单元和其他类型之间的某种分离（特别是“64 EPI”和“64 PE”）。\n",
    "因此，基于此可视化，PC1 似乎对于区分 TE 细胞类型（32TE 和 64TE）与其他细胞类型最有用。然而，PCA 是一种线性方法，可能无法捕获数据中的复杂模式。根据具体的生物学问题，其他更复杂的方法或 PC 的组合可能更合适。\n",
    "\n",
    "请注意，这种解释是基于对情节的视觉评估。为了进行更严格的评估，您可以考虑使用统计方法或机器学习算法来量化 PC 区分不同细胞类型的性能。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 哪对组合的 PC 1,2 和 3 能够最好地将 2 细胞阶段与其余阶段分开（例如 PC 1&2、1&3 或 2&3）？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>PC1</th>\n",
       "      <th>PC2</th>\n",
       "      <th>PC3</th>\n",
       "      <th>Cell Type</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>-1.102578</td>\n",
       "      <td>-0.787688</td>\n",
       "      <td>4.719307</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>-1.113674</td>\n",
       "      <td>-1.724675</td>\n",
       "      <td>5.337998</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>-0.276250</td>\n",
       "      <td>-2.363237</td>\n",
       "      <td>5.136926</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>-0.773030</td>\n",
       "      <td>-2.517412</td>\n",
       "      <td>4.607077</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-0.514028</td>\n",
       "      <td>-1.778956</td>\n",
       "      <td>5.076129</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        PC1       PC2       PC3 Cell Type\n",
       "0 -1.102578 -0.787688  4.719307         1\n",
       "1 -1.113674 -1.724675  5.337998         1\n",
       "2 -0.276250 -2.363237  5.136926         1\n",
       "3 -0.773030 -2.517412  4.607077         1\n",
       "4 -0.514028 -1.778956  5.076129         1"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Perform PCA again with 3 components this time\n",
    "pca = PCA(n_components=3)\n",
    "principalComponents = pca.fit_transform(data_std)\n",
    "\n",
    "# Create a dataframe with the first three principal components\n",
    "PCA_df_3 = pd.DataFrame(data = principalComponents, columns = ['PC1', 'PC2', 'PC3'])\n",
    "\n",
    "# Add the cell labels to the PCA dataframe\n",
    "PCA_df_3['Cell Type'] = cell_labels\n",
    "\n",
    "PCA_df_3.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_1423/513176829.py:6: UserWarning: No data for colormapping provided via 'c'. Parameters 'cmap' will be ignored\n",
      "  plt.scatter(subset[pc1], subset[pc2], label=str(cell), cmap=colormap, color=colormap(idx))\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 98796 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 93104 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 90976 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "# Define a function to create scatter plots for different pairs of PCs\n",
    "def create_scatter_plot(pc1, pc2, df, cell_type, colormap):\n",
    "    unique_cell_types = df[cell_type].unique()\n",
    "    for idx, cell in enumerate(unique_cell_types):\n",
    "        subset = df[df[cell_type] == cell]\n",
    "        plt.scatter(subset[pc1], subset[pc2], label=str(cell), cmap=colormap, color=colormap(idx))\n",
    "    plt.xlabel(pc1)\n",
    "    plt.ylabel(pc2)\n",
    "    plt.legend(title=cell_type, bbox_to_anchor=(1.05, 1), loc='upper left')\n",
    "    plt.grid(True)\n",
    "    plt.show()\n",
    "\n",
    "# Create scatter plots for different pairs of PCs\n",
    "plt.figure(figsize=(10,8))\n",
    "plt.title('PCA on the Dataset (PC1 & PC2, colored by cell type)')\n",
    "create_scatter_plot('PC1', 'PC2', PCA_df_3, 'Cell Type', colormap)\n",
    "\n",
    "plt.figure(figsize=(10,8))\n",
    "plt.title('PCA on the Dataset (PC1 & PC3, colored by cell type)')\n",
    "create_scatter_plot('PC1', 'PC3', PCA_df_3, 'Cell Type', colormap)\n",
    "\n",
    "plt.figure(figsize=(10,8))\n",
    "plt.title('PCA on the Dataset (PC2 & PC3, colored by cell type)')\n",
    "create_scatter_plot('PC2', 'PC3', PCA_df_3, 'Cell Type', colormap)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上图显示了由不同主成分对定义的空间中的不同细胞类型：PC1 和 PC2、PC1 和 PC3 以及 PC2 和 PC3。每种细胞类型都由不同的颜色表示。\n",
    "\n",
    "经过目视检查，似乎 PC1 和 PC3 的组合提供了“2”细胞阶段与其余阶段最明显的分离。该结论基于“2”细胞阶段数据点（橙色）与 PC3 轴上的其他点很大程度上分离的观察结果。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面这段代码展示了如何使用肘部法则来确定最佳聚类数。\n",
    "\n",
    "肘部法则是一种常用的聚类分析方法，用于确定最佳聚类数。它的基本思想是，随着聚类数的增加，聚类结果的惯性会逐渐减小，但减小的速度会逐渐变缓。当聚类数增加到一定程度时，惯性的减小速度会急剧变缓，形成一个类似于手肘的拐点。这个拐点所对应的聚类数就是最佳聚类数。因此，肘部法则的目的就是通过绘制肘部曲线来找到这个拐点，以确定最佳聚类数。\n",
    "\n",
    "聚类结果的惯性是指聚类结果与聚类中心的距离平方和。在 KMeans 算法中，惯性是一个重要的评估指标，用于衡量聚类结果的好坏。聚类结果的惯性越小，说明聚类结果与聚类中心的距离越近，聚类效果越好。因此，在使用 KMeans 算法进行聚类时，通常会尝试不同的聚类数，并选择惯性最小的聚类结果作为最终的聚类结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 43548 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 重新导入必要的库\n",
    "import pandas as pd\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.cluster import KMeans\n",
    "from sklearn.decomposition import PCA\n",
    "import matplotlib.pyplot as plt\n",
    "from mpl_toolkits.mplot3d import Axes3D\n",
    "\n",
    "# 重新加载并预处理数据\n",
    "\n",
    "# 加载 CSV 数据\n",
    "guo_data = pd.read_csv(\"/mnt/d/coding/codes/ML/2022-23/week 4/handout-solutions/GuoData.csv\")\n",
    "\n",
    "# 删除不必要的列\n",
    "guo_data = guo_data.drop(columns=[\"Unnamed: 0\"])\n",
    "\n",
    "# 检查是否有缺失值\n",
    "missing_values = guo_data.isnull().sum().sum()\n",
    "\n",
    "# 标准化数据\n",
    "if missing_values == 0:\n",
    "    scaler = StandardScaler()\n",
    "    guo_data_standardized = scaler.fit_transform(guo_data)\n",
    "else:\n",
    "    guo_data_standardized = None\n",
    "\n",
    "# 打印缺失值数量和标准化后的数据\n",
    "missing_values, guo_data_standardized\n",
    "\n",
    "# 使用肘部法则确定最佳聚类数\n",
    "inertia = []\n",
    "clusters_range = range(1, 15)  # 检查最多 14 个聚类\n",
    "\n",
    "for cluster_num in clusters_range:\n",
    "    kmeans = KMeans(n_clusters=cluster_num,  n_init=10)\n",
    "    kmeans.fit(guo_data_standardized)\n",
    "    inertia.append(kmeans.inertia_)\n",
    "\n",
    "# 绘制肘部曲线\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(clusters_range, inertia, marker='o', linestyle='--')\n",
    "plt.title('Elbow Method')\n",
    "plt.xlabel('Number of Clusters')\n",
    "plt.ylabel('Inertia')\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Actb</th>\n",
       "      <th>Ahcy</th>\n",
       "      <th>Aqp3</th>\n",
       "      <th>Atp12a</th>\n",
       "      <th>Bmp4</th>\n",
       "      <th>Cdx2</th>\n",
       "      <th>Creb312</th>\n",
       "      <th>Cebpa</th>\n",
       "      <th>Dab2</th>\n",
       "      <th>DppaI</th>\n",
       "      <th>...</th>\n",
       "      <th>Sall4</th>\n",
       "      <th>Sox17</th>\n",
       "      <th>Snail</th>\n",
       "      <th>Sox13</th>\n",
       "      <th>Tcfap2a</th>\n",
       "      <th>Tcfap2c</th>\n",
       "      <th>Tcf23</th>\n",
       "      <th>Utf1</th>\n",
       "      <th>Tspan8</th>\n",
       "      <th>Cluster</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>-0.541050</td>\n",
       "      <td>1.203007</td>\n",
       "      <td>-1.030746</td>\n",
       "      <td>-1.064808</td>\n",
       "      <td>-0.494782</td>\n",
       "      <td>0.167143</td>\n",
       "      <td>1.369092</td>\n",
       "      <td>-1.083061</td>\n",
       "      <td>-0.668057</td>\n",
       "      <td>1.553758</td>\n",
       "      <td>...</td>\n",
       "      <td>1.793476</td>\n",
       "      <td>-0.783185</td>\n",
       "      <td>1.408063</td>\n",
       "      <td>0.031991</td>\n",
       "      <td>0.351257</td>\n",
       "      <td>1.078982</td>\n",
       "      <td>-0.942981</td>\n",
       "      <td>-1.348892</td>\n",
       "      <td>1.051999</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>-0.680832</td>\n",
       "      <td>1.355306</td>\n",
       "      <td>-2.456375</td>\n",
       "      <td>-1.234350</td>\n",
       "      <td>-0.645494</td>\n",
       "      <td>-1.003868</td>\n",
       "      <td>1.207595</td>\n",
       "      <td>-1.208023</td>\n",
       "      <td>-0.800388</td>\n",
       "      <td>1.435306</td>\n",
       "      <td>...</td>\n",
       "      <td>1.782172</td>\n",
       "      <td>-1.532477</td>\n",
       "      <td>1.361172</td>\n",
       "      <td>0.501715</td>\n",
       "      <td>-1.082362</td>\n",
       "      <td>0.930112</td>\n",
       "      <td>-1.064399</td>\n",
       "      <td>-1.469397</td>\n",
       "      <td>0.996275</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>-1.056038</td>\n",
       "      <td>1.280447</td>\n",
       "      <td>-2.046133</td>\n",
       "      <td>-1.439795</td>\n",
       "      <td>-0.828121</td>\n",
       "      <td>-0.983404</td>\n",
       "      <td>1.460032</td>\n",
       "      <td>-1.359447</td>\n",
       "      <td>-0.530701</td>\n",
       "      <td>1.340283</td>\n",
       "      <td>...</td>\n",
       "      <td>1.567402</td>\n",
       "      <td>-3.194157</td>\n",
       "      <td>1.301777</td>\n",
       "      <td>0.445219</td>\n",
       "      <td>-0.031284</td>\n",
       "      <td>1.005767</td>\n",
       "      <td>-1.211529</td>\n",
       "      <td>-1.615421</td>\n",
       "      <td>0.651393</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>-0.732331</td>\n",
       "      <td>1.326911</td>\n",
       "      <td>-2.464234</td>\n",
       "      <td>-1.244323</td>\n",
       "      <td>-0.654359</td>\n",
       "      <td>-0.947023</td>\n",
       "      <td>1.265609</td>\n",
       "      <td>-1.215373</td>\n",
       "      <td>-0.765212</td>\n",
       "      <td>1.431401</td>\n",
       "      <td>...</td>\n",
       "      <td>1.915556</td>\n",
       "      <td>-2.962515</td>\n",
       "      <td>1.349710</td>\n",
       "      <td>-1.875957</td>\n",
       "      <td>-1.699892</td>\n",
       "      <td>1.059458</td>\n",
       "      <td>-1.071541</td>\n",
       "      <td>-1.476485</td>\n",
       "      <td>0.699586</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-0.629333</td>\n",
       "      <td>1.244308</td>\n",
       "      <td>-1.316815</td>\n",
       "      <td>-1.304162</td>\n",
       "      <td>-0.707552</td>\n",
       "      <td>-1.429070</td>\n",
       "      <td>0.895578</td>\n",
       "      <td>0.007785</td>\n",
       "      <td>-0.644606</td>\n",
       "      <td>1.381937</td>\n",
       "      <td>...</td>\n",
       "      <td>1.761825</td>\n",
       "      <td>-1.265379</td>\n",
       "      <td>1.320533</td>\n",
       "      <td>0.609864</td>\n",
       "      <td>-0.413826</td>\n",
       "      <td>0.888624</td>\n",
       "      <td>-1.114394</td>\n",
       "      <td>-1.519017</td>\n",
       "      <td>0.798985</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 49 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "       Actb      Ahcy      Aqp3    Atp12a      Bmp4      Cdx2   Creb312  \\\n",
       "0 -0.541050  1.203007 -1.030746 -1.064808 -0.494782  0.167143  1.369092   \n",
       "1 -0.680832  1.355306 -2.456375 -1.234350 -0.645494 -1.003868  1.207595   \n",
       "2 -1.056038  1.280447 -2.046133 -1.439795 -0.828121 -0.983404  1.460032   \n",
       "3 -0.732331  1.326911 -2.464234 -1.244323 -0.654359 -0.947023  1.265609   \n",
       "4 -0.629333  1.244308 -1.316815 -1.304162 -0.707552 -1.429070  0.895578   \n",
       "\n",
       "      Cebpa      Dab2     DppaI  ...     Sall4     Sox17     Snail     Sox13  \\\n",
       "0 -1.083061 -0.668057  1.553758  ...  1.793476 -0.783185  1.408063  0.031991   \n",
       "1 -1.208023 -0.800388  1.435306  ...  1.782172 -1.532477  1.361172  0.501715   \n",
       "2 -1.359447 -0.530701  1.340283  ...  1.567402 -3.194157  1.301777  0.445219   \n",
       "3 -1.215373 -0.765212  1.431401  ...  1.915556 -2.962515  1.349710 -1.875957   \n",
       "4  0.007785 -0.644606  1.381937  ...  1.761825 -1.265379  1.320533  0.609864   \n",
       "\n",
       "    Tcfap2a   Tcfap2c     Tcf23      Utf1    Tspan8  Cluster  \n",
       "0  0.351257  1.078982 -0.942981 -1.348892  1.051999        1  \n",
       "1 -1.082362  0.930112 -1.064399 -1.469397  0.996275        1  \n",
       "2 -0.031284  1.005767 -1.211529 -1.615421  0.651393        1  \n",
       "3 -1.699892  1.059458 -1.071541 -1.476485  0.699586        1  \n",
       "4 -0.413826  0.888624 -1.114394 -1.519017  0.798985        1  \n",
       "\n",
       "[5 rows x 49 columns]"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Re-applying KMeans with 3 clusters due to the interrupted state\n",
    "kmeans = KMeans(n_clusters=3 , n_init=10)\n",
    "guo_data_clusters = kmeans.fit_predict(guo_data_standardized)\n",
    "\n",
    "# Add the cluster labels to the original data for further analysis\n",
    "guo_data[\"Cluster\"] = guo_data_clusters\n",
    "\n",
    "# Display the first few rows of the data with cluster labels\n",
    "guo_data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "KMeans聚类结果0中，出现原始类别['32 ICM', '64 PE', '64 EPI']的次数分别是[45, 44, 19]\n",
      "KMeans聚类结果1中，出现原始类别['16', '8', '4']的次数分别是[75, 43, 23]\n",
      "KMeans聚类结果2中，出现原始类别['64 TE', '32 TE', '32 ICM']的次数分别是[95, 56, 3]\n",
      "DBSCAN聚类结果-1中，出现原始类别['64 TE', '16', '32 TE']的次数分别是[96, 75, 60]\n",
      "高斯混合模型聚类结果1中，出现原始类别['32 ICM', '64 PE', '64 EPI']的次数分别是[45, 44, 19]\n",
      "高斯混合模型聚类结果0中，出现原始类别['16', '8', '4']的次数分别是[75, 43, 23]\n",
      "高斯混合模型聚类结果2中，出现原始类别['64 TE', '32 TE', '32 ICM']的次数分别是[95, 56, 3]\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "from sklearn.cluster import KMeans, DBSCAN\n",
    "from sklearn.mixture import GaussianMixture\n",
    "\n",
    "# 读取数据集\n",
    "guo_data = pd.read_csv(\"/mnt/d/coding/codes/ML/2022-23/week 4/handout-solutions/GuoData.csv\")\n",
    "\n",
    "# 获取原始类别\n",
    "labels = guo_data.iloc[:, 0]\n",
    "\n",
    "# 获取特征数据\n",
    "features = guo_data.iloc[:, 1:]\n",
    "\n",
    "# 使用KMeans算法进行聚类\n",
    "kmeans = KMeans(n_clusters=3, n_init=10).fit(features)\n",
    "\n",
    "# 使用DBSCAN算法进行聚类\n",
    "dbscan = DBSCAN(eps=0.5, min_samples=5).fit(features)\n",
    "\n",
    "# 使用高斯混合模型进行聚类\n",
    "gmm = GaussianMixture(n_components=3, covariance_type='full').fit(features)\n",
    "\n",
    "# 获取聚类结果\n",
    "kmeans_clusters = kmeans.labels_\n",
    "dbscan_clusters = dbscan.labels_\n",
    "gmm_clusters = gmm.predict(features)\n",
    "\n",
    "# 将聚类结果与原始类别进行比较\n",
    "kmeans_comparison = pd.DataFrame({'原始类别': labels, '聚类结果': kmeans_clusters})\n",
    "dbscan_comparison = pd.DataFrame({'原始类别': labels, '聚类结果': dbscan_clusters})\n",
    "gmm_comparison = pd.DataFrame({'原始类别': labels, '聚类结果': gmm_clusters})\n",
    "\n",
    "# 统计每个聚类结果中出现次数最多的前三个原始类别\n",
    "for cluster in kmeans_comparison['聚类结果'].unique():\n",
    "    counts = kmeans_comparison['原始类别'][kmeans_comparison['聚类结果'] == cluster].value_counts()\n",
    "    max_counts = counts.nlargest(3)\n",
    "    max_labels = max_counts.index.tolist()\n",
    "    max_counts = max_counts.tolist()\n",
    "    print(f'KMeans聚类结果{cluster}中，出现原始类别{max_labels}的次数分别是{max_counts}')\n",
    "\n",
    "for cluster in dbscan_comparison['聚类结果'].unique():\n",
    "    counts = dbscan_comparison['原始类别'][dbscan_comparison['聚类结果'] == cluster].value_counts()\n",
    "    max_counts = counts.nlargest(3)\n",
    "    max_labels = max_counts.index.tolist()\n",
    "    max_counts = max_counts.tolist()\n",
    "    print(f'DBSCAN聚类结果{cluster}中，出现原始类别{max_labels}的次数分别是{max_counts}')\n",
    "\n",
    "for cluster in gmm_comparison['聚类结果'].unique():\n",
    "    counts = gmm_comparison['原始类别'][gmm_comparison['聚类结果'] == cluster].value_counts()\n",
    "    max_counts = counts.nlargest(3)\n",
    "    max_labels = max_counts.index.tolist()\n",
    "    max_counts = max_counts.tolist()\n",
    "    print(f'高斯混合模型聚类结果{cluster}中，出现原始类别{max_labels}的次数分别是{max_counts}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 107980 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 111340 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import pandas as pd \n",
    "from sklearn.decomposition import PCA\n",
    "import matplotlib.pyplot as plt \n",
    "\n",
    " \n",
    "\n",
    "# 使用PCA进行降维\n",
    "pca = PCA(n_components=2)\n",
    "reduced_features = pca.fit_transform(features)\n",
    " \n",
    "\n",
    "# 使用KMeans算法进行聚类\n",
    "kmeans = KMeans(n_clusters=3, n_init=10).fit(reduced_features)\n",
    "\n",
    "# 使用高斯混合模型进行聚类\n",
    "gmm = GaussianMixture(n_components=3, covariance_type='full').fit(reduced_features)\n",
    "\n",
    "# 获取聚类结果\n",
    "kmeans_clusters = kmeans.labels_\n",
    "gmm_clusters = gmm.predict(reduced_features)\n",
    "\n",
    "# 将聚类结果与原始类别进行比较\n",
    "kmeans_comparison = pd.DataFrame({'原始类别': labels, '聚类结果': kmeans_clusters})\n",
    "gmm_comparison = pd.DataFrame({'原始类别': labels, '聚类结果': gmm_clusters})\n",
    "\n",
    "# 绘制KMeans聚类结果的散点图\n",
    "plt.figure(figsize=(8, 6))\n",
    "plt.scatter(reduced_features[:, 0], reduced_features[:, 1], c=kmeans_clusters)\n",
    "plt.title('KMeans ')\n",
    "plt.xlabel('Principal Component 1')\n",
    "plt.ylabel('Principal Component 2')\n",
    "plt.show()\n",
    "\n",
    "# 绘制高斯混合模型聚类结果的散点图\n",
    "plt.figure(figsize=(8, 6))\n",
    "plt.scatter(reduced_features[:, 0], reduced_features[:, 1], c=gmm_clusters)\n",
    "plt.title('Goassian Mixture Model')\n",
    "plt.xlabel('Principal Component 1')\n",
    "plt.ylabel('Principal Component 2')\n",
    "plt.show()\n",
    " \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 137896 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 140676 characters]",
      "text/plain": [
       "<Figure size 800x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.decomposition import PCA\n",
    "import matplotlib.pyplot as plt \n",
    "\n",
    "# 使用PCA进行降维\n",
    "pca = PCA(n_components=3)\n",
    "reduced_features = pca.fit_transform(features)\n",
    "\n",
    "# 绘制KMeans聚类结果的三维散点图\n",
    "fig = plt.figure(figsize=(8, 6))\n",
    "ax = fig.add_subplot(111, projection='3d')\n",
    "ax.scatter(reduced_features[:, 0], reduced_features[:, 1], reduced_features[:, 2], c=kmeans_clusters)\n",
    "ax.set_title('KMeans')\n",
    "ax.set_xlabel('Principal Component 1')\n",
    "ax.set_ylabel('Principal Component 2')\n",
    "ax.set_zlabel('Principal Component 3')\n",
    "plt.show()\n",
    "\n",
    "# 绘制高斯混合模型聚类结果的三维散点图\n",
    "fig = plt.figure(figsize=(8, 6))\n",
    "ax = fig.add_subplot(111, projection='3d')\n",
    "ax.scatter(reduced_features[:, 0], reduced_features[:, 1], reduced_features[:, 2], c=gmm_clusters)\n",
    "ax.set_title('Gorssian mixture model')\n",
    "ax.set_xlabel('Principal Component 1')\n",
    "ax.set_ylabel('Principal Component 2')\n",
    "ax.set_zlabel('Principal Component 3')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch20.1",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
