seabornでページ遷移などを可視化する

# はじめに
ウェブサービスのユーザがどのページからどのページに移っていっているのかとか、どの工程からどの工程に仕掛品が流れていったのかなどをPythonで可視化したい。
ここでは仮に以下のようなどのページからどのページに移っていったのかについて集計したデータがあったとする。

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>from</th>
      <th>to</th>
      <th>count</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>A</td>
      <td>A</td>
      <td>111</td>
    </tr>
    <tr>
      <th>1</th>
      <td>A</td>
      <td>B</td>
      <td>1120</td>
    </tr>
    <tr>
      <th>2</th>
      <td>A</td>
      <td>C</td>
      <td>1230</td>
    </tr>
    <tr>
      <th>3</th>
      <td>B</td>
      <td>A</td>
      <td>214</td>
    </tr>
    <tr>
      <th>4</th>
      <td>B</td>
      <td>B</td>
      <td>1225</td>
    </tr>
    <tr>
      <th>5</th>
      <td>B</td>
      <td>C</td>
      <td>1216</td>
    </tr>
    <tr>
      <th>6</th>
      <td>C</td>
      <td>A</td>
      <td>327</td>
    </tr>
    <tr>
      <th>7</th>
      <td>C</td>
      <td>C</td>
      <td>2319</td>
    </tr>
  </tbody>
</table>
</div>

こんな感じでページ→ページの遷移数と遷移確率行列的なものを可視化したい。

![c_matrix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/fd1812d5-0290-d7e5-2300-ce90e61d2027.png)

![p_matrix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/6399151d-f838-19de-0c5e-9c531c8abdd6.png)

# 実装
以下でpandas, seaborn, matplotlibを使ってJupyter上で可視化する。

```python
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
```


```python
df = pd.DataFrame({'from': ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C'],
                  'to': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'C'],
                  'count': [111, 1120, 1230, 214, 1225, 1216, 327, 2319]})
df  # C→Bのページ遷移は0件とする
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>from</th>
      <th>to</th>
      <th>count</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>A</td>
      <td>A</td>
      <td>111</td>
    </tr>
    <tr>
      <th>1</th>
      <td>A</td>
      <td>B</td>
      <td>1120</td>
    </tr>
    <tr>
      <th>2</th>
      <td>A</td>
      <td>C</td>
      <td>1230</td>
    </tr>
    <tr>
      <th>3</th>
      <td>B</td>
      <td>A</td>
      <td>214</td>
    </tr>
    <tr>
      <th>4</th>
      <td>B</td>
      <td>B</td>
      <td>1225</td>
    </tr>
    <tr>
      <th>5</th>
      <td>B</td>
      <td>C</td>
      <td>1216</td>
    </tr>
    <tr>
      <th>6</th>
      <td>C</td>
      <td>A</td>
      <td>327</td>
    </tr>
    <tr>
      <th>7</th>
      <td>C</td>
      <td>C</td>
      <td>2319</td>
    </tr>
  </tbody>
</table>
</div>




```python
pages = sorted(list(set(df['from'].values) | set(df['to'].values)))
pages
```




    ['A', 'B', 'C']




```python
count_matrix = pd.DataFrame(index=pages, columns=pages, dtype=float)
count_matrix
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>A</th>
      <th>B</th>
      <th>C</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>A</th>
      <td>NaN</td>
      <td>NaN</td>
      <td>NaN</td>
    </tr>
    <tr>
      <th>B</th>
      <td>NaN</td>
      <td>NaN</td>
      <td>NaN</td>
    </tr>
    <tr>
      <th>C</th>
      <td>NaN</td>
      <td>NaN</td>
      <td>NaN</td>
    </tr>
  </tbody>
</table>
</div>




```python
for i in zip(df['from'].values, df['to'].values, df['count'].values):
    count_matrix.at[i[0], i[1]] = i[2]
```


```python
count_matrix.fillna(0, inplace=True)
```


```python
row_sum = count_matrix.sum(axis=1)
row_sum
```




    A    2461.0
    B    2655.0
    C    2646.0
    dtype: float64




```python
probabilistic_matrix = count_matrix.div(row_sum, axis=0)
probabilistic_matrix
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>A</th>
      <th>B</th>
      <th>C</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>A</th>
      <td>0.045104</td>
      <td>0.455100</td>
      <td>0.499797</td>
    </tr>
    <tr>
      <th>B</th>
      <td>0.080603</td>
      <td>0.461394</td>
      <td>0.458004</td>
    </tr>
    <tr>
      <th>C</th>
      <td>0.123583</td>
      <td>0.000000</td>
      <td>0.876417</td>
    </tr>
  </tbody>
</table>
</div>




```python
sns.heatmap(count_matrix, annot=True, cmap='coolwarm', fmt='g', vmin=0)
```





    
![c_matrix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/20e40b3d-c0d7-3e90-7599-9334d841f567.png)

    



```python
sns.heatmap(probabilistic_matrix, annot=True, cmap='coolwarm', fmt='.3f', vmin=0, vmax=1)
plt.ylabel('from')
plt.xlabel('to')
plt.show()
```


![p_matrix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/17eaf859-e550-2d7e-b225-a9488102103f.png)