Skip to content

Instantly share code, notes, and snippets.

@caiyili
Created November 10, 2023 01:32
Show Gist options
  • Save caiyili/5eae662a2aa509fdde2cf8fb7555c860 to your computer and use it in GitHub Desktop.
Save caiyili/5eae662a2aa509fdde2cf8fb7555c860 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "c1d12945-34bd-4ced-afce-0797b286ac29",
"metadata": {},
"source": [
"# pandas 库使用"
]
},
{
"cell_type": "markdown",
"id": "8a2b659c-532d-4c30-80da-289f6e4716b6",
"metadata": {},
"source": [
"## 1、创建一个 dataframe"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "0b7a0e28-1a97-4a54-8675-9a113ee69892",
"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>ts</th>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>flow</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>57</td>\n",
" <td>43</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2023-01-01 00:00:01</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>11</td>\n",
" <td>32</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>40</td>\n",
" <td>59</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2023-01-01 00:00:03</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>25</td>\n",
" <td>28</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>20</td>\n",
" <td>29</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>2023-01-01 00:00:05</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>7</td>\n",
" <td>19</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>10</td>\n",
" <td>33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>2023-01-01 00:00:07</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>16</td>\n",
" <td>33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>35</td>\n",
" <td>33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>2023-01-01 00:00:09</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>15</td>\n",
" <td>26</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ts roomId stream user flow audioLevel framerate\n",
"0 2023-01-01 00:00:00 20131110 XXXXXXXX 111 push 57 43\n",
"1 2023-01-01 00:00:01 20131110 XXXXXXXX 222 pull 11 32\n",
"2 2023-01-01 00:00:02 20131110 XXXXXXXX 111 push 40 59\n",
"3 2023-01-01 00:00:03 20131110 XXXXXXXX 222 pull 25 28\n",
"4 2023-01-01 00:00:04 20131110 XXXXXXXX 111 push 20 29\n",
"5 2023-01-01 00:00:05 20131110 XXXXXXXX 222 pull 7 19\n",
"6 2023-01-01 00:00:06 20131110 XXXXXXXX 111 push 10 33\n",
"7 2023-01-01 00:00:07 20131110 XXXXXXXX 222 pull 16 33\n",
"8 2023-01-01 00:00:08 20131110 XXXXXXXX 111 push 35 33\n",
"9 2023-01-01 00:00:09 20131110 XXXXXXXX 222 pull 15 26"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import datetime\n",
"import random\n",
"\n",
"# 生成测试数据\n",
"num_rows = 10\n",
"\n",
"df = pd.DataFrame(dict(\n",
" ts = pd.date_range('2023-01-01', periods=num_rows, freq='S'),\n",
" roomId = ['20131110']*num_rows,\n",
" stream = ['XXXXXXXX'] * num_rows,\n",
" user = ['111','222'] * (num_rows//2),\n",
" flow = ['push','pull'] * (num_rows//2),\n",
" audioLevel = [57, 11, 40, 25, 20, 7, 10, 16, 35, 15],\n",
" framerate = [43, 32, 59, 28, 29, 19, 33, 33, 33, 26],\n",
"))\n",
"df"
]
},
{
"cell_type": "markdown",
"id": "26df3e1b-7790-4f3f-a5fa-d96330e202c9",
"metadata": {},
"source": [
"## 2、拆分 pull / push 数据\n",
"\n",
"1. 按照 flow 字段,把 push / pull 数据拆分开,以方便后面把同一条流每个时间点的推流和拉流数据合并到一起"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "bb69c33b-5697-4479-abd9-c03ac678f209",
"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>ts</th>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>flow</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2023-01-01 00:00:01</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>11</td>\n",
" <td>32</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2023-01-01 00:00:03</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>25</td>\n",
" <td>28</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>2023-01-01 00:00:05</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>7</td>\n",
" <td>19</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>2023-01-01 00:00:07</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>16</td>\n",
" <td>33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>2023-01-01 00:00:09</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>15</td>\n",
" <td>26</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ts roomId stream user flow audioLevel framerate\n",
"1 2023-01-01 00:00:01 20131110 XXXXXXXX 222 pull 11 32\n",
"3 2023-01-01 00:00:03 20131110 XXXXXXXX 222 pull 25 28\n",
"5 2023-01-01 00:00:05 20131110 XXXXXXXX 222 pull 7 19\n",
"7 2023-01-01 00:00:07 20131110 XXXXXXXX 222 pull 16 33\n",
"9 2023-01-01 00:00:09 20131110 XXXXXXXX 222 pull 15 26"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_pull = df[ df['flow']=='pull' ]\n",
"df_pull"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "7e42dadc-a56a-4ec7-98d9-44f2cb511d0a",
"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>ts</th>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>flow</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>57</td>\n",
" <td>43</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>40</td>\n",
" <td>59</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>20</td>\n",
" <td>29</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>10</td>\n",
" <td>33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>35</td>\n",
" <td>33</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ts roomId stream user flow audioLevel framerate\n",
"0 2023-01-01 00:00:00 20131110 XXXXXXXX 111 push 57 43\n",
"2 2023-01-01 00:00:02 20131110 XXXXXXXX 111 push 40 59\n",
"4 2023-01-01 00:00:04 20131110 XXXXXXXX 111 push 20 29\n",
"6 2023-01-01 00:00:06 20131110 XXXXXXXX 111 push 10 33\n",
"8 2023-01-01 00:00:08 20131110 XXXXXXXX 111 push 35 33"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_push = df[ df['flow']=='push' ]\n",
"df_push"
]
},
{
"cell_type": "markdown",
"id": "bfa67102-b119-44ca-a474-38516387ce57",
"metadata": {},
"source": [
"## 3、时间对齐 - Resample\n",
"\n",
"1. 推流端上报的时间点、与拉流端上报的时间,是不对齐的\n",
"2. 中间数据是可能缺失的,也可能会有多的\n",
"3. 还有可能采样频率不一样(客户端 2s 一次,服务端 5s 一次)\n",
"4. 对齐前需要先按 roomId/stream 来分组\n",
"\n",
"这些情况都可以通过 resample 来对齐"
]
},
{
"cell_type": "markdown",
"id": "d140d076-4275-40c4-a57b-d07e8689f4c0",
"metadata": {},
"source": [
"### 3.1 拉流数据 df_pull,Resample"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "0baf8312-f962-43be-8449-ded7cd0e925c",
"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>ts</th>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>flow</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2023-01-01 00:00:01</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>11</td>\n",
" <td>32</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2023-01-01 00:00:03</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>25</td>\n",
" <td>28</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>2023-01-01 00:00:05</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>7</td>\n",
" <td>19</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>2023-01-01 00:00:07</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>16</td>\n",
" <td>33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>2023-01-01 00:00:09</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>pull</td>\n",
" <td>15</td>\n",
" <td>26</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ts roomId stream user flow audioLevel framerate\n",
"1 2023-01-01 00:00:01 20131110 XXXXXXXX 222 pull 11 32\n",
"3 2023-01-01 00:00:03 20131110 XXXXXXXX 222 pull 25 28\n",
"5 2023-01-01 00:00:05 20131110 XXXXXXXX 222 pull 7 19\n",
"7 2023-01-01 00:00:07 20131110 XXXXXXXX 222 pull 16 33\n",
"9 2023-01-01 00:00:09 20131110 XXXXXXXX 222 pull 15 26"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_pull"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "cded323b-7a15-4924-a17c-f493eac56c8e",
"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></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" </tr>\n",
" <tr>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>ts</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"5\" valign=\"top\">20131110</th>\n",
" <th rowspan=\"5\" valign=\"top\">XXXXXXXX</th>\n",
" <th rowspan=\"5\" valign=\"top\">222</th>\n",
" <th>2023-01-01 00:00:00</th>\n",
" <td>11.0</td>\n",
" <td>32.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:02</th>\n",
" <td>25.0</td>\n",
" <td>28.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:04</th>\n",
" <td>7.0</td>\n",
" <td>19.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:06</th>\n",
" <td>16.0</td>\n",
" <td>33.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:08</th>\n",
" <td>15.0</td>\n",
" <td>26.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" audioLevel framerate\n",
"roomId stream user ts \n",
"20131110 XXXXXXXX 222 2023-01-01 00:00:00 11.0 32.0\n",
" 2023-01-01 00:00:02 25.0 28.0\n",
" 2023-01-01 00:00:04 7.0 19.0\n",
" 2023-01-01 00:00:06 16.0 33.0\n",
" 2023-01-01 00:00:08 15.0 26.0"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_pull_resample = df_pull.drop(\n",
" columns=['flow']\n",
").set_index(\n",
" 'ts'\n",
").groupby(\n",
" ['roomId','stream', 'user']\n",
").resample(\n",
" '2s'\n",
").mean()\n",
"df_pull_resample"
]
},
{
"cell_type": "markdown",
"id": "5730cf4e-288d-4d73-b32b-5f9b1d3ffcc9",
"metadata": {},
"source": [
"### 3.2 推流数据 df_pull Resample"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "6c453c27-6645-481b-aff9-c15afebd39b9",
"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>ts</th>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>flow</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>57</td>\n",
" <td>43</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>40</td>\n",
" <td>59</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>20</td>\n",
" <td>29</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>10</td>\n",
" <td>33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>111</td>\n",
" <td>push</td>\n",
" <td>35</td>\n",
" <td>33</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ts roomId stream user flow audioLevel framerate\n",
"0 2023-01-01 00:00:00 20131110 XXXXXXXX 111 push 57 43\n",
"2 2023-01-01 00:00:02 20131110 XXXXXXXX 111 push 40 59\n",
"4 2023-01-01 00:00:04 20131110 XXXXXXXX 111 push 20 29\n",
"6 2023-01-01 00:00:06 20131110 XXXXXXXX 111 push 10 33\n",
"8 2023-01-01 00:00:08 20131110 XXXXXXXX 111 push 35 33"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_push"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "96696c2d-2bd6-4ed8-b208-7d36d153e407",
"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></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" </tr>\n",
" <tr>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>ts</th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th rowspan=\"5\" valign=\"top\">20131110</th>\n",
" <th rowspan=\"5\" valign=\"top\">XXXXXXXX</th>\n",
" <th rowspan=\"5\" valign=\"top\">111</th>\n",
" <th>2023-01-01 00:00:00</th>\n",
" <td>57.0</td>\n",
" <td>43.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:02</th>\n",
" <td>40.0</td>\n",
" <td>59.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:04</th>\n",
" <td>20.0</td>\n",
" <td>29.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:06</th>\n",
" <td>10.0</td>\n",
" <td>33.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:08</th>\n",
" <td>35.0</td>\n",
" <td>33.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" audioLevel framerate\n",
"roomId stream user ts \n",
"20131110 XXXXXXXX 111 2023-01-01 00:00:00 57.0 43.0\n",
" 2023-01-01 00:00:02 40.0 59.0\n",
" 2023-01-01 00:00:04 20.0 29.0\n",
" 2023-01-01 00:00:06 10.0 33.0\n",
" 2023-01-01 00:00:08 35.0 33.0"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_push_resample = df_push.drop(\n",
" columns=['flow']\n",
").set_index(\n",
" 'ts'\n",
").groupby(\n",
" ['roomId', 'stream', 'user']\n",
").resample(\n",
" '2s'\n",
").mean()\n",
"df_push_resample"
]
},
{
"cell_type": "markdown",
"id": "35da0d76-cbe7-4517-ab96-59ba7c46958b",
"metadata": {},
"source": [
"## 4、合并推流与拉流数据 merge"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "ae1015a6-6702-4c8f-8064-cef1828c1b37",
"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>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>ts</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" <th>user_push</th>\n",
" <th>audioLevel_push</th>\n",
" <th>framerate_push</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>11.0</td>\n",
" <td>32.0</td>\n",
" <td>111</td>\n",
" <td>57.0</td>\n",
" <td>43.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>25.0</td>\n",
" <td>28.0</td>\n",
" <td>111</td>\n",
" <td>40.0</td>\n",
" <td>59.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>7.0</td>\n",
" <td>19.0</td>\n",
" <td>111</td>\n",
" <td>20.0</td>\n",
" <td>29.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>16.0</td>\n",
" <td>33.0</td>\n",
" <td>111</td>\n",
" <td>10.0</td>\n",
" <td>33.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>15.0</td>\n",
" <td>26.0</td>\n",
" <td>111</td>\n",
" <td>35.0</td>\n",
" <td>33.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" roomId stream user ts audioLevel framerate \\\n",
"0 20131110 XXXXXXXX 222 2023-01-01 00:00:00 11.0 32.0 \n",
"1 20131110 XXXXXXXX 222 2023-01-01 00:00:02 25.0 28.0 \n",
"2 20131110 XXXXXXXX 222 2023-01-01 00:00:04 7.0 19.0 \n",
"3 20131110 XXXXXXXX 222 2023-01-01 00:00:06 16.0 33.0 \n",
"4 20131110 XXXXXXXX 222 2023-01-01 00:00:08 15.0 26.0 \n",
"\n",
" user_push audioLevel_push framerate_push \n",
"0 111 57.0 43.0 \n",
"1 111 40.0 59.0 \n",
"2 111 20.0 29.0 \n",
"3 111 10.0 33.0 \n",
"4 111 35.0 33.0 "
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_merged = pd.merge(\n",
" df_pull_resample.reset_index(),\n",
" df_push_resample.reset_index(),\n",
" how='left',\n",
" on=['roomId','stream', 'ts'],\n",
" suffixes=[\"\", \"_push\"],\n",
")\n",
"df_merged"
]
},
{
"cell_type": "markdown",
"id": "df258c46-59a8-435d-9d8c-e5d854b9da6b",
"metadata": {},
"source": [
"## 5、获取音视频开关事件\n",
"\n",
"1. 开关事件,不像 stats 上报,他不是固定频率上报,而是发生了就有,没发生就没有"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "e96f46a6-a87c-4a4a-8e86-79158965a5b2",
"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>user</th>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>video</th>\n",
" <th>audio</th>\n",
" </tr>\n",
" <tr>\n",
" <th>ts</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2023-01-01 00:00:00.111</th>\n",
" <td>111</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:01.555</th>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:05.555</th>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>False</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:07.555</th>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>None</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2023-01-01 00:00:06.555</th>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>None</td>\n",
" <td>False</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" user roomId stream video audio\n",
"ts \n",
"2023-01-01 00:00:00.111 111 20131110 XXXXXXXX True True\n",
"2023-01-01 00:00:01.555 222 20131110 XXXXXXXX True True\n",
"2023-01-01 00:00:05.555 222 20131110 XXXXXXXX False None\n",
"2023-01-01 00:00:07.555 222 20131110 XXXXXXXX True None\n",
"2023-01-01 00:00:06.555 222 20131110 XXXXXXXX None False"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_event = pd.DataFrame(dict(\n",
" ts = [\n",
" pd.to_datetime('2023-01-01 00:00:00.111'), \n",
" pd.to_datetime('2023-01-01 00:00:01.555'), \n",
" pd.to_datetime('2023-01-01 00:00:05.555'), \n",
" pd.to_datetime('2023-01-01 00:00:07.555'), \n",
" pd.to_datetime('2023-01-01 00:00:06.555'), \n",
" ],\n",
" user = ['111'] + ['222'] * 4,\n",
" roomId = ['20131110'] * 5,\n",
" stream = ['XXXXXXXX'] * 5,\n",
" video = [True, True, False, True, None],\n",
" audio = [True, True, None, None, False],\n",
")).set_index('ts')\n",
"df_event"
]
},
{
"cell_type": "markdown",
"id": "1da84844-25fa-4c54-8405-dbb8517da52b",
"metadata": {},
"source": [
"### 6、把音视频开关事件也进行重采样\n",
"\n",
"#### 给 df_event 加一条最大时间,这样重采样的时候就可以自动填充中间的时间\n",
"\n",
"1. groupby().apply(func) 表示先进行分组,再每个分组中再执行一个函数\n",
"1. last() 表示重采样的时候,采用这个周期内最后一个值\n",
"2. ffill() 表示空值用前一个值填充。在这里的体现是,如果没有发生新的开关事件,状态就保持不变\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "f81925e9-d6fa-442c-841c-a8bc32016e53",
"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>ts</th>\n",
" <th>user</th>\n",
" <th>roomId</th>\n",
" <th>stream</th>\n",
" <th>video</th>\n",
" <th>audio</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>111</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>111</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>111</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>111</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>111</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>222</td>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ts user roomId stream video audio\n",
"0 2023-01-01 00:00:00 111 20131110 XXXXXXXX True True\n",
"1 2023-01-01 00:00:02 111 20131110 XXXXXXXX True True\n",
"2 2023-01-01 00:00:04 111 20131110 XXXXXXXX True True\n",
"3 2023-01-01 00:00:06 111 20131110 XXXXXXXX True True\n",
"4 2023-01-01 00:00:08 111 20131110 XXXXXXXX True True\n",
"5 2023-01-01 00:00:00 222 20131110 XXXXXXXX True True\n",
"6 2023-01-01 00:00:02 222 20131110 XXXXXXXX True True\n",
"7 2023-01-01 00:00:04 222 20131110 XXXXXXXX False True\n",
"8 2023-01-01 00:00:06 222 20131110 XXXXXXXX True False\n",
"9 2023-01-01 00:00:08 222 20131110 XXXXXXXX True False"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"max_ts = df_merged['ts'].max()\n",
"\n",
"def group_resample_fill(sub_df):\n",
" ## 添加一条记录,设置填充的最大值\n",
" sub_df.loc[max_ts, :] = sub_df.iloc[-1].tolist()\n",
" ## 重采样,填充空值\n",
" sub_df = sub_df.resample('2s').last().ffill()\n",
" return sub_df.reset_index()\n",
" \n",
"df_event_resample = df_event.groupby(['roomId','stream','user']).apply(group_resample_fill).reset_index(drop=True)\n",
"df_event_resample"
]
},
{
"cell_type": "markdown",
"id": "23302e15-f588-457f-8555-411b187495f1",
"metadata": {},
"source": [
"## 7、把 event 和 stats 数据进行合并\n",
"\n",
"1. 现在 events 数据和 stats 数据采样周期已经是一致的,可以进行合并了\n",
"2. 这里用户有推流的,也有拉流的,需要合并2次"
]
},
{
"cell_type": "markdown",
"id": "03348e97-e92a-4730-a334-87537c98462d",
"metadata": {},
"source": [
"### 合并拉流用户事件"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "6b060815-e779-46cd-8970-27b67a8e5c9e",
"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>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>ts</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" <th>user_push</th>\n",
" <th>audioLevel_push</th>\n",
" <th>framerate_push</th>\n",
" <th>video</th>\n",
" <th>audio</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>11.0</td>\n",
" <td>32.0</td>\n",
" <td>111</td>\n",
" <td>57.0</td>\n",
" <td>43.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>25.0</td>\n",
" <td>28.0</td>\n",
" <td>111</td>\n",
" <td>40.0</td>\n",
" <td>59.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>7.0</td>\n",
" <td>19.0</td>\n",
" <td>111</td>\n",
" <td>20.0</td>\n",
" <td>29.0</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>16.0</td>\n",
" <td>33.0</td>\n",
" <td>111</td>\n",
" <td>10.0</td>\n",
" <td>33.0</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>15.0</td>\n",
" <td>26.0</td>\n",
" <td>111</td>\n",
" <td>35.0</td>\n",
" <td>33.0</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" roomId stream user ts audioLevel framerate \\\n",
"0 20131110 XXXXXXXX 222 2023-01-01 00:00:00 11.0 32.0 \n",
"1 20131110 XXXXXXXX 222 2023-01-01 00:00:02 25.0 28.0 \n",
"2 20131110 XXXXXXXX 222 2023-01-01 00:00:04 7.0 19.0 \n",
"3 20131110 XXXXXXXX 222 2023-01-01 00:00:06 16.0 33.0 \n",
"4 20131110 XXXXXXXX 222 2023-01-01 00:00:08 15.0 26.0 \n",
"\n",
" user_push audioLevel_push framerate_push video audio \n",
"0 111 57.0 43.0 True True \n",
"1 111 40.0 59.0 True True \n",
"2 111 20.0 29.0 False True \n",
"3 111 10.0 33.0 True False \n",
"4 111 35.0 33.0 True False "
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_merged_with_pull_event = pd.merge(\n",
" df_merged,\n",
" df_event_resample,\n",
" how='left',\n",
" on=['roomId','stream','user', 'ts'],\n",
")\n",
"df_merged_with_pull_event"
]
},
{
"cell_type": "markdown",
"id": "c1480ea9-5f22-402e-8bb2-65576a7dd78b",
"metadata": {},
"source": [
"### 合并推流用户事件"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "9c11ae6d-c337-46a8-a574-306986441842",
"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>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>ts</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" <th>user_push</th>\n",
" <th>audioLevel_push</th>\n",
" <th>framerate_push</th>\n",
" <th>video</th>\n",
" <th>audio</th>\n",
" <th>video_push</th>\n",
" <th>audio_push</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>11.0</td>\n",
" <td>32.0</td>\n",
" <td>111</td>\n",
" <td>57.0</td>\n",
" <td>43.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>25.0</td>\n",
" <td>28.0</td>\n",
" <td>111</td>\n",
" <td>40.0</td>\n",
" <td>59.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>7.0</td>\n",
" <td>19.0</td>\n",
" <td>111</td>\n",
" <td>20.0</td>\n",
" <td>29.0</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>16.0</td>\n",
" <td>33.0</td>\n",
" <td>111</td>\n",
" <td>10.0</td>\n",
" <td>33.0</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>15.0</td>\n",
" <td>26.0</td>\n",
" <td>111</td>\n",
" <td>35.0</td>\n",
" <td>33.0</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" roomId stream user ts audioLevel framerate \\\n",
"0 20131110 XXXXXXXX 222 2023-01-01 00:00:00 11.0 32.0 \n",
"1 20131110 XXXXXXXX 222 2023-01-01 00:00:02 25.0 28.0 \n",
"2 20131110 XXXXXXXX 222 2023-01-01 00:00:04 7.0 19.0 \n",
"3 20131110 XXXXXXXX 222 2023-01-01 00:00:06 16.0 33.0 \n",
"4 20131110 XXXXXXXX 222 2023-01-01 00:00:08 15.0 26.0 \n",
"\n",
" user_push audioLevel_push framerate_push video audio video_push \\\n",
"0 111 57.0 43.0 True True True \n",
"1 111 40.0 59.0 True True True \n",
"2 111 20.0 29.0 False True True \n",
"3 111 10.0 33.0 True False True \n",
"4 111 35.0 33.0 True False True \n",
"\n",
" audio_push \n",
"0 True \n",
"1 True \n",
"2 True \n",
"3 True \n",
"4 True "
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_merged_with_both_event = pd.merge(\n",
" df_merged_with_pull_event,\n",
" df_event_resample.rename(columns={'user':'user_push'}),\n",
" how='left',\n",
" on=['roomId','stream','user_push','ts'],\n",
" suffixes=[\"\", \"_push\"],\n",
")\n",
"df_merged_with_both_event"
]
},
{
"cell_type": "markdown",
"id": "212cae8c-c710-4609-a432-310150d7258b",
"metadata": {},
"source": [
"## 8、按窗口轮转取最近几条的平均值 - rolling\n",
"\n",
"1. 每个点上报的数据,是瞬时值,可以取前2个时间点的平均一下\n",
"2. 采用窗口函数轮转的方式,每个点都与前2个点一起算平均值\n",
"3. 这里用到的是 pandas 的 rolling 函数\n",
"\n",
"> 实际情况中,我们也是要先分组,同一个分组下相邻的数据才能进行窗口轮转"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "e8c6cbda-e300-4bc3-807f-70743e6a7db7",
"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>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>ts</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" <th>user_push</th>\n",
" <th>audioLevel_push</th>\n",
" <th>framerate_push</th>\n",
" <th>video</th>\n",
" <th>audio</th>\n",
" <th>video_push</th>\n",
" <th>audio_push</th>\n",
" <th>framerate_mean</th>\n",
" <th>audioLevel_mean</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>11.0</td>\n",
" <td>32.0</td>\n",
" <td>111</td>\n",
" <td>57.0</td>\n",
" <td>43.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>25.0</td>\n",
" <td>28.0</td>\n",
" <td>111</td>\n",
" <td>40.0</td>\n",
" <td>59.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>30.0</td>\n",
" <td>18.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>7.0</td>\n",
" <td>19.0</td>\n",
" <td>111</td>\n",
" <td>20.0</td>\n",
" <td>29.0</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>23.5</td>\n",
" <td>16.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>16.0</td>\n",
" <td>33.0</td>\n",
" <td>111</td>\n",
" <td>10.0</td>\n",
" <td>33.0</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>26.0</td>\n",
" <td>11.5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>15.0</td>\n",
" <td>26.0</td>\n",
" <td>111</td>\n",
" <td>35.0</td>\n",
" <td>33.0</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>29.5</td>\n",
" <td>15.5</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" roomId stream user ts audioLevel framerate \\\n",
"0 20131110 XXXXXXXX 222 2023-01-01 00:00:00 11.0 32.0 \n",
"1 20131110 XXXXXXXX 222 2023-01-01 00:00:02 25.0 28.0 \n",
"2 20131110 XXXXXXXX 222 2023-01-01 00:00:04 7.0 19.0 \n",
"3 20131110 XXXXXXXX 222 2023-01-01 00:00:06 16.0 33.0 \n",
"4 20131110 XXXXXXXX 222 2023-01-01 00:00:08 15.0 26.0 \n",
"\n",
" user_push audioLevel_push framerate_push video audio video_push \\\n",
"0 111 57.0 43.0 True True True \n",
"1 111 40.0 59.0 True True True \n",
"2 111 20.0 29.0 False True True \n",
"3 111 10.0 33.0 True False True \n",
"4 111 35.0 33.0 True False True \n",
"\n",
" audio_push framerate_mean audioLevel_mean \n",
"0 True NaN NaN \n",
"1 True 30.0 18.0 \n",
"2 True 23.5 16.0 \n",
"3 True 26.0 11.5 \n",
"4 True 29.5 15.5 "
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dfm = df_merged_with_both_event\n",
"dfm[['framerate_mean', 'audioLevel_mean']] = dfm[['framerate','audioLevel']].rolling(window=2).mean()\n",
"dfm"
]
},
{
"cell_type": "markdown",
"id": "ddc7b964-e428-4d7d-9b3c-c2a63b38cdcc",
"metadata": {},
"source": [
"## 8、过滤有问题的数据"
]
},
{
"cell_type": "markdown",
"id": "d1aaffbd-d086-412c-a8b3-bb9ac35ae375",
"metadata": {},
"source": [
"### 先给每条数据打上标记,是否有问题\n",
"\n",
"1. 打标记的方式就是,增加一列,计算数据是否有问题"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "05f8a9b0-e36a-4fbd-b23a-a45f52f62ca5",
"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>roomId</th>\n",
" <th>stream</th>\n",
" <th>user</th>\n",
" <th>ts</th>\n",
" <th>audioLevel</th>\n",
" <th>framerate</th>\n",
" <th>user_push</th>\n",
" <th>audioLevel_push</th>\n",
" <th>framerate_push</th>\n",
" <th>video</th>\n",
" <th>audio</th>\n",
" <th>video_push</th>\n",
" <th>audio_push</th>\n",
" <th>framerate_mean</th>\n",
" <th>audioLevel_mean</th>\n",
" <th>video_abnormal</th>\n",
" <th>audio_abnormal</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:00</td>\n",
" <td>11.0</td>\n",
" <td>32.0</td>\n",
" <td>111</td>\n",
" <td>57.0</td>\n",
" <td>43.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:02</td>\n",
" <td>25.0</td>\n",
" <td>28.0</td>\n",
" <td>111</td>\n",
" <td>40.0</td>\n",
" <td>59.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>30.0</td>\n",
" <td>18.0</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:04</td>\n",
" <td>7.0</td>\n",
" <td>19.0</td>\n",
" <td>111</td>\n",
" <td>20.0</td>\n",
" <td>29.0</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>23.5</td>\n",
" <td>16.0</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:06</td>\n",
" <td>16.0</td>\n",
" <td>33.0</td>\n",
" <td>111</td>\n",
" <td>10.0</td>\n",
" <td>33.0</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>26.0</td>\n",
" <td>11.5</td>\n",
" <td>False</td>\n",
" <td>False</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>20131110</td>\n",
" <td>XXXXXXXX</td>\n",
" <td>222</td>\n",
" <td>2023-01-01 00:00:08</td>\n",
" <td>15.0</td>\n",
" <td>26.0</td>\n",
" <td>111</td>\n",
" <td>35.0</td>\n",
" <td>33.0</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" <td>True</td>\n",
" <td>True</td>\n",
" <td>29.5</td>\n",
" <td>15.5</td>\n",
" <td>True</td>\n",
" <td>False</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" roomId stream user ts audioLevel framerate \\\n",
"0 20131110 XXXXXXXX 222 2023-01-01 00:00:00 11.0 32.0 \n",
"1 20131110 XXXXXXXX 222 2023-01-01 00:00:02 25.0 28.0 \n",
"2 20131110 XXXXXXXX 222 2023-01-01 00:00:04 7.0 19.0 \n",
"3 20131110 XXXXXXXX 222 2023-01-01 00:00:06 16.0 33.0 \n",
"4 20131110 XXXXXXXX 222 2023-01-01 00:00:08 15.0 26.0 \n",
"\n",
" user_push audioLevel_push framerate_push video audio video_push \\\n",
"0 111 57.0 43.0 True True True \n",
"1 111 40.0 59.0 True True True \n",
"2 111 20.0 29.0 False True True \n",
"3 111 10.0 33.0 True False True \n",
"4 111 35.0 33.0 True False True \n",
"\n",
" audio_push framerate_mean audioLevel_mean video_abnormal audio_abnormal \n",
"0 True NaN NaN True True \n",
"1 True 30.0 18.0 True True \n",
"2 True 23.5 16.0 False True \n",
"3 True 26.0 11.5 False False \n",
"4 True 29.5 15.5 True False "
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def is_video_abnormal(r):\n",
" return (\n",
" r.video_push == True\n",
" and r.video == True\n",
" and r.framerate < r.framerate_push * 0.99\n",
" )\n",
" \n",
"def is_audio_abnormal(r):\n",
" return (\n",
" r.audio_push == True\n",
" and r.audio == True\n",
" and r.audioLevel < r.audioLevel_push * 0.95\n",
" )\n",
"\n",
"df_raw = df_merged_with_both_event\n",
"df_raw['video_abnormal'] = df_raw.apply(is_video_abnormal, axis=1)\n",
"df_raw['audio_abnormal'] = df_raw.apply(is_audio_abnormal, axis=1)\n",
"df_raw\n"
]
},
{
"cell_type": "markdown",
"id": "62ede41c-d799-45b1-b531-8288a82f5875",
"metadata": {},
"source": [
"## 9、计算连续异常的时间段,过滤时间段少于 n 秒的\n",
"\n",
"1. 实现一个连续的计数器\n",
"2. 连续时长超过 N 秒的,记到结果时,其它的丢弃\n",
"\n",
"> 具体实现方式这里不展示了"
]
},
{
"cell_type": "markdown",
"id": "266ee54b-0da9-4a65-a3d5-ffb84a351075",
"metadata": {},
"source": [
"## 10、数据转为图形展示\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "63608b39-7f16-4106-89be-e3ac8b7b376d",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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aNjsr9mvXz8mTJjAb7/9hsVioV+/fgA0adKE559/nltuuYXg4GDuvPNOAB599FFatmyJv78/TZs25amnnqKoqMj+2s8++ywdO3bkk08+IT4+nsDAQP71r39RUlLCK6+8QnR0NJGRkbz44osOMR87dox//OMfREREEBwczIABA1i7dm2583700UckJibie3yhyp9++onevXsTGhpKeHg4l112GTt27LA/LzExEYBOnTo5vD+Ajz76iKSkJHx9fWndujWTJ0+u0HUUERGpKvV4S/1y8KDZo718OaxbB8XFZW0BAdCli9mz3aULBAY6L05xfSEhMH68mWw/+ih8+SV88AH83//B44/D/fdrpfvqYBiOpftqk79/paYQfPrpp4wYMYLly5ezcuVK7rzzTuLj47njjjsq9PxJkyYxa9YsvvjiC+Lj49mzZw97ThqdM3bsWF555RVeffVV3nrrLYYNG8bu3bsJadCAP20FAHSy+uIBfPPNNzz22GOsX7+eb775xqEX+bXXXuPpp5/mmWeese8LCgpi6tSpxMbGsm7dOu644w6CgoJ45JFH7Mfs2LGDH3/8kZ9++okdO3ZwzTXXsHPnTlq2bMmCBQtYvHgxt99+O4MGDaJHjx4AXHvttfj5+fHjjz8SEhLC+++/z8CBA9m6dSthxxcp3L59O19//TXffPMNHse//MzJyWH06NF06NCB7Oxsnn76aa666irWrFmD1Wpl+fLldO/enTlz5tC2bVv7+5s2bRpPP/00b7/9Np06dWL16tXccccdBAQEcOutt1b4eoqIiFSGEm9xbzabWW+5NNnetcuxPSbGHD7evTskJZm9lSLVKTERvvgCFi40V0JfuRLGjIH334eXX4Zrr9X873ORm+u8L8mys80v7CooLi6OiRMnYrFYaNWqFevWrWPixIkVTrxTU1Np0aIFvXv3xmKxkJCQUO6Y4cOHc+ONNwLw0ksvMWnSJJYvX86Fgwdz8r+ysLAw/P398fb2Jjo62qFtwIABPPjggw77nnzySfvjJk2a8NBDDzFjxgyHxNtms/HJJ58QFBREmzZt6N+/P1u2bOGHH37AarXSqlUrXn75ZX799Vd69OjBwoULWb58Oenp6fj4+ABm0j9z5ky++uore297YWEhn332GREREfbXGjp0qEN8n3zyCREREWzcuJF27drZjw0PD3d4f8888wwTJkzg6quvBsye8Y0bN/L+++8r8RYRkRpTqaHmzz77LBaLxWFr3bq1vT0/P5+RI0cSHh5OYGAgQ4cO5YCGVUptKygwy329/Tbcdpu52vQXX5hJt9VqDhcfPtxc+Oq998zh5O3bK+mWmtW7t/nv8rPPoFEj89/j9deb+5cvd3Z0Ugt69uyJ5YQvWZKTk9m2bRslJy7eeAbDhw9nzZo1tGrVinvvvZf//e9/5Y7p0KGD/XFAQADBwcGkp6fjYbHQxcOPLh5+eFTgi56uXbuW2/ef//yHXr16ER0dTWBgIE8++SSpqakOxzRp0oSgoCD7z1FRUbRp0wbrCaUVo6KiSE9PB2Dt2rVkZ2fb7xtKt5SUFIdh4wkJCQ5JN8C2bdu48cYbadq0KcHBwTRp0gSgXEwnysnJYceOHYwYMcLh9V544QWH1xMREalulc402rZty5w5c8pOcEKy8sADDzB79my+/PJLQkJCGDVqFFdffTWLFi2qnmhFTufw4bKF0f78EwoLy9r8/KBzZ7NXu0sXCA52XpxSv1mtcPPNcPXVMGGC2eO9eLFZ+33YMBg3zlzITyrO39+xxF9tv3Y1slgsDnO+AYc51J07dyYlJYUff/yROXPmcN111zFo0CC++uor+zFeJ5Wvs1gs2Gy2SscScFJP/pIlSxg2bBhjx45l8ODBhISEMGPGDCZMmOBw3Kle/0wxZWdnExMTw/z588vFcGJZs5PjARgyZAgJCQl8+OGHxMbGYrPZaNeuHYUn/v4/Sfbxfysffvihfah7KQ+t3yEiIjWo0om3p6dnuSFpABkZGXz88cdMnz6dAQMGADBlyhSSkpJYunQpPXv2PPdoRUoZBuzcWVbya/t2x/bISDPR7tYN2rVTLWWpWwIC4OmnzdEWTzwBn34K06bBN9+YIzQeeURrDFSUxVKp4d7OtGzZMoefly5dSosWLewJX0REBPv377e3b9u2jdyT5q8HBwdz/fXXc/3113PNNddw0UUXceTIEftc6JqyePFiEhISeOKJJ+z7du/efc7n7dy5M2lpaXh6etp7rCvi8OHDbNmyhQ8//JA+ffoAsHDhQodjSud0nziiICoqitjYWHbu3MmwYcPOOX4REZGKqnTivW3bNmJjY/H19SU5OZlx48YRHx/PqlWrKCoqYtCgQfZjW7duTXx8PEuWLDlt4l1QUEBBQYH958zMzCq8DakXCgvN3uzly815socOlbVZLNCyZVnJr4QEzZuVuq9RI5g6Fe65x5z//fvv8Pzz8NFH8NJLcMstZi+5uIXU1FRGjx7NXXfdxR9//MFbb73l0GM8YMAA3n77bZKTkykpKeHRRx916C1+/fXXiYmJoVOnTlitVr788kuio6MdeoZPx2YY7DHM3vM4ixfWSv5+bNGiBampqcyYMYNu3boxe/Zsvv3220qd41QGDRpEcnIyV155Ja+88gotW7Zk3759zJ49m6uuuuqUQ94BGjRoQHh4OB988AExMTGkpqby2GOPORwTGRmJn58fP/30E40bN8bX15eQkBDGjh3LvffeS0hICBdddBEFBQWsXLmSo0ePMnr06HN+TyIiIqdSqcS7R48eTJ06lVatWrF//37Gjh1Lnz59WL9+PWlpaXh7e5e7AYiKiiItLe205xw3bhxjx46tUvBSDxw9aibZK1bAmjWQn1/W5uMDnTqZyXbXrtCggdPCFDknXbrAggVmj/cjj5ijOW67Dd56CyZOhL59nR2hVINbbrmFvLw8unfvjoeHB/fdd5998TCACRMmcNttt9GnTx9iY2N58803WbVqlb09KCiIV155hW3btuHh4UG3bt3si5adjQEcNMye38aWyo8Auvzyy3nggQcYNWoUBQUFXHrppTz11FM8++yzlT7XiSwWCz/88ANPPPEEt912GwcPHiQ6Opq+ffsSFRV12udZrVZmzJjBvffeS7t27WjVqhWTJk1yKBnm6enJpEmTeO6553j66afp06cP8+fP5x//+Af+/v68+uqrPPzwwwQEBNC+fXvuv//+c3ovIiIiZ2IxTp5QVgnHjh0jISGB119/HT8/P2677TaH3muA7t27079/f15++eVTnuNUPd5xcXFkZGQQXIfn4uYYNgLzNgGQ/WsKAbYqf4xyIsOA3bvLhpBv3WruKxUeXtar3aGDWSNZ3M+QIc6OwHkKCmDSJHjhBSgdAXT11fDKK9CsmXNjqwPy8/NJSUlxqOfsCvr160fHjh154403nPL6NsMgzTDLJ0ZbPCvd412fueq/Oal5uhcUqUEuci+YmZlJSEhIhXLXc1rGOTQ0lJYtW7J9+3YuvPBCCgsLOXbsmEOv94EDB045J7yUj4+PvYSI1FNFRbB+fdniaMdXu7Vr3rws2W7aVEPIxb35+MDDD8Ot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jZy3PtO1ch119VqNHDmS9evXs3DhwmqKyD3UtevVqlUr1qxZQ0ZGBl999RW33norCxYscPnkuzrUlWu1Z88e7rvvPn755Rd8fX1rJCZXV1euFeDQq9OhQwd69OhBQkICX3zxBSNGjKjO8FxSXbpWNpuNrl278tJLLwHQqVMn1q9fz3vvvcett95a3SG6nLp0rU708ccfc/HFFxMbG1tNEbm+unStvvjiC6ZNm8b06dNp27Yta9as4f777yc2NrZG/79ymx7vhg0b4uHhUW4FvQMHDhAdHU10dDSFhYUcO3bslO2nEx0dfdpzlraX7quO8wYHB+Pn53fW9+PK3O1auTN3vlajRo3i+++/59dff6Vx48anPacrcdfr5e3tTfPmzenSpQvjxo3jvPPO48033zzteV2Bu12rVatWkZ6eTufOnfH09MTT05MFCxYwadIkPD09KSkpOe256zp3u1anEhoaSsuWLdm+fftpz+sK3PFaxcTElPuSMSkpyeWnBrjjtSq1e/du5syZwz/+8Y/Tns+VuOO1evjhh+293u3bt+fmm2/mgQceqPERW26TeHt7e9OlSxeHb1NsNhtz584lOTmZLl264OXl5dC+ZcsWUlNTzzhXMDk5udw3NL/88ov9OYmJiURHRzsck5mZybJly87pvGd7P67M3a6VO3PHa2UYBqNGjeLbb79l3rx5JCYmnuVTcB3ueL1OxWazUVBQcMZj6jp3u1YDBw5k3bp1rFmzxr517dqVYcOGsWbNGjw8PCrwqdRN7natTiU7O5sdO3Y4DNd0Re54rXr16lWu5OXWrVtJSEg47XldgTteq1JTpkwhMjKSSy+99LTncyXueK1yc3OxWh3TYA8PD2w222nPWy1qdOm2WjZjxgzDx8fHmDp1qrFx40bjzjvvNEJDQ420tDTDMMyl7uPj44158+YZK1euNJKTk43k5GSHcwwYMMB466237D8vWrTI8PT0NF577TVj06ZNxjPPPHPKpe5DQ0ON//73v8aff/5pXHHFFeWWur/55puNxx57zP5z6VL3Dz/8sLFp0ybjnXfeOWU5sTO9H1fmbtcqKyvLWL16tbF69WoDMF5//XVj9erVxu7du6v9s6tt7nat7r77biMkJMSYP3++Q9mP3Nzcav/snMHdrtdjjz1mLFiwwEhJSTH+/PNP47HHHjMsFovxv//9r9o/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",
"text/plain": [
"<Figure size 1000x450 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"def draw_graph(df):\n",
" metrics = [\n",
" 'framerate',\n",
" 'audioLevel',\n",
" ]\n",
" _, axes = plt.subplots(\n",
" nrows=len(metrics),\n",
" ncols=1,\n",
" figsize=(10, 2*len(metrics)+0.5),\n",
" sharex=False,\n",
" )\n",
" for i,m in enumerate(metrics):\n",
" ax = axes[i]\n",
" # 拉流的线\n",
" ax.plot(df['ts'], df[m],\n",
" label='pull ' + m, color='green',)\n",
" # 推流的折线\n",
" ax.plot(df['ts'], df[m + \"_push\"],\n",
" label='push ' + m, color='red',)\n",
"\n",
" # 把识别出来的异常区域标记出来\n",
" pre_ts = None\n",
" for _, e in df.iterrows():\n",
" ## 如果视频有异常,给标记出来\n",
" if e.video_abnormal and m == 'framerate' and pre_ts != None:\n",
" ax.axvspan(pre_ts, e.ts, facecolor='red', alpha=0.3)\n",
" ## 如果音频有异常,给标记出来\n",
" if e.audio_abnormal and m == 'audioLevel' and pre_ts != None:\n",
" ax.axvspan(pre_ts, e.ts, facecolor='yellow', alpha=0.3)\n",
" pre_ts = e.ts\n",
"\n",
" # 把开关事件标记上 开启用实线,关闭用虚线\n",
" pre_item = pd.Series()\n",
" for _, e in df.iterrows():\n",
" if m == 'framerate':\n",
" if pre_item.empty or (e.video != pre_item.video):\n",
" style = '-' if e.video else ':'\n",
" ax.axvline(e.ts, color='#00f5d4', linestyle=style)\n",
" else:\n",
" if pre_item.empty or (e.audio != pre_item.audio):\n",
" style = '-' if e.audio else ':'\n",
" ax.axvline(e.ts, color='#00f5d4', linestyle=style)\n",
" \n",
" pre_item = e\n",
" legend = ax.legend(loc='upper center')\n",
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
"draw_graph(df_raw)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dda51c87-0a56-42f1-b8a9-0d54ac07d4d7",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment