├── .github └── workflows │ └── fal_workflow.yml ├── .gitignore ├── README.md ├── analysis └── .gitkeep ├── analyze_sentiment.ipynb ├── data ├── .gitkeep ├── covid19_italy_region.csv ├── raw_o3_values.csv └── zendesk_ticket_data.csv ├── dbt_project.yml ├── fal_scripts ├── anomaly_detection.py ├── anomaly_detection │ ├── 2021-11-20-2054-CET.jpg │ ├── 2021-11-20-2204-CET.jpg │ ├── 2021-11-20-2207-CET.jpg │ ├── 2021-11-20-2215-CET.jpg │ └── 2021-11-20-2322-CET.jpg ├── anomaly_detection_other │ ├── distance_between_samples.jpg │ └── distance_between_samples_bounded.jpg ├── forecast_slack.py ├── list_owners_of_models.py ├── load_o3_data.py ├── send_datadog_event.py ├── slack.py ├── upload_to_gcs.py ├── upload_to_s3.py ├── write_to_firestore.py └── zendesk_sentiment_analysis.py ├── macros └── .gitkeep ├── models ├── boston.sql ├── lombardia_covid.sql ├── miami.sql ├── schema.yml ├── stg_counties.sql ├── stg_o3values.sql ├── stg_zendesk_ticket_data.sql └── zendesk_ticket_metrics.sql ├── profiles.yml ├── requirements.txt ├── snapshots └── .gitkeep ├── tests └── .gitkeep └── weighted_label.png /.github/workflows/fal_workflow.yml: -------------------------------------------------------------------------------- 1 | name: Run fal scripts 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | test: 8 | 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | python: ["3.8.x"] 13 | dbt: ["0.20.1", "0.21.1"] 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - uses: actions/setup-python@v2 19 | with: 20 | python-version: ${{ matrix.python }} 21 | 22 | - name: Install dependencies 23 | run: | 24 | pip install --upgrade --upgrade-strategy eager -r requirements.txt 25 | pip install dbt==${{ matrix.dbt }} 26 | 27 | - name: Setup secret key 28 | env: 29 | SERVICE_ACCOUNT_KEY: ${{ secrets.SERVICE_ACCOUNT_KEY }} 30 | run: | 31 | echo "$SERVICE_ACCOUNT_KEY" > $HOME/keyfile.json 32 | ls -la $HOME/keyfile.json 33 | echo 'keyfile is ready' 34 | 35 | - name: Run dbt and fal 36 | env: 37 | GCLOUD_PROJECT: ${{ secrets.GCLOUD_PROJECT }} 38 | BQ_DATASET: ${{ secrets.BQ_DATASET }} 39 | SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} 40 | SLACK_BOT_CHANNEL: ${{ secrets.SLACK_BOT_CHANNEL }} 41 | DD_API_KEY: ${{ secrets.DD_API_KEY }} 42 | DD_APP_KEY: ${{ secrets.DD_APP_KEY }} 43 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 44 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 45 | FAL_STATS_ENABLED: false 46 | run: | 47 | export KEYFILE_DIR=$HOME 48 | dbt seed --profiles-dir . 49 | dbt run --profiles-dir . --full-refresh 50 | fal run --profiles-dir . 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target/ 3 | dbt_modules/ 4 | logs/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Fal example dbt project 2 | 3 | This is an example dbt project that uses [fal](https://github.com/fal-ai/fal) 4 | 5 | To get started, install the dependency requirements: 6 | 7 | ```bash 8 | pip install -r requirements.txt 9 | ``` 10 | 11 | Copy `profiles.yml` to `.dbt` directory: 12 | 13 | ```bash 14 | mkdir $HOME/.dbt 15 | cp profiles.yml $HOME/.dbt/ 16 | ``` 17 | 18 | Setup up the necessary environment variables: 19 | 20 | ```bash 21 | export KEYFILE_DIR=$HOME 22 | export GCLOUD_PROJECT='your_gcloud_project_id' 23 | export BQ_DATASET='your_bigquery_dataset_id' 24 | export SLACK_BOT_TOKEN='your_slack_bot_token' 25 | export SLACK_BOT_CHANNEL='your_slack_bot_channel' 26 | export DD_API_KEY="your_datadog_api_key" 27 | export DD_APP_KEY="your_datadog_app_key" 28 | ``` 29 | 30 | You can now try to run dbt and fal: 31 | 32 | ```bash 33 | dbt seed 34 | dbt run 35 | fal run 36 | ``` 37 | 38 | See example details: 39 | 40 | - [schema.yml](models/schema.yml) for model configurations 41 | - [script examples](fal_scripts/) 42 | - [profiles.yml](profiles.yml) for example profile 43 | - [requirements.txt](requirements.txt) 44 | - [fal_workflow.yml](.github/workflows/fal_workflow.yml) for example Github Action workflow 45 | 46 | -------------------------------------------------------------------------------- /analysis/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/analysis/.gitkeep -------------------------------------------------------------------------------- /analyze_sentiment.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 3, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import os\n", 10 | "os.environ['GCLOUD_PROJECT'] = 'XXX'\n", 11 | "os.environ['BQ_DATASET'] = 'YYY'" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 8, 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "name": "stdout", 21 | "output_type": "stream", 22 | "text": [ 23 | "[['results', 'ticket_data_sentiment_analysis']]\n", 24 | "{'model.fal_dbt_examples.boston': , 'model.fal_dbt_examples.zendesk_ticket_metrics': , 'model.fal_dbt_examples.stg_o3values': , 'model.fal_dbt_examples.stg_zendesk_ticket_data': , 'model.fal_dbt_examples.stg_counties': }\n" 25 | ] 26 | } 27 | ], 28 | "source": [ 29 | "from fal import FalDbt\n", 30 | "\n", 31 | "faldbt = FalDbt(profiles_dir=\"./\", project_dir=\"./\")\n", 32 | "print(faldbt.list_sources())\n", 33 | "print(faldbt.list_models())" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 45, 39 | "metadata": {}, 40 | "outputs": [ 41 | { 42 | "data": { 43 | "text/html": [ 44 | "
\n", 45 | "\n", 58 | "\n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | "
idlabelscore
011013NEGATIVE0.8679937124252319
66171POSITIVE0.9987179040908813
121595POSITIVE0.9567179083824158
1811071POSITIVE0.9949386119842529
2416988POSITIVE0.9998757839202881
3014173POSITIVE0.9995272159576416
364721NEGATIVE0.9998005032539368
421404NEGATIVE0.9994755387306213
481966NEGATIVE0.9922933578491211
546605NEGATIVE0.9995110034942627
\n", 130 | "
" 131 | ], 132 | "text/plain": [ 133 | " id label score\n", 134 | "0 11013 NEGATIVE 0.8679937124252319\n", 135 | "6 6171 POSITIVE 0.9987179040908813\n", 136 | "12 1595 POSITIVE 0.9567179083824158\n", 137 | "18 11071 POSITIVE 0.9949386119842529\n", 138 | "24 16988 POSITIVE 0.9998757839202881\n", 139 | "30 14173 POSITIVE 0.9995272159576416\n", 140 | "36 4721 NEGATIVE 0.9998005032539368\n", 141 | "42 1404 NEGATIVE 0.9994755387306213\n", 142 | "48 1966 NEGATIVE 0.9922933578491211\n", 143 | "54 6605 NEGATIVE 0.9995110034942627" 144 | ] 145 | }, 146 | "execution_count": 45, 147 | "metadata": {}, 148 | "output_type": "execute_result" 149 | } 150 | ], 151 | "source": [ 152 | "sentiments = faldbt.source('results', 'ticket_data_sentiment_analysis')\n", 153 | "sentiments = sentiments.drop_duplicates('id')\n", 154 | "sentiments" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": 46, 160 | "metadata": {}, 161 | "outputs": [ 162 | { 163 | "data": { 164 | "text/html": [ 165 | "
\n", 166 | "\n", 179 | "\n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | "
id_fivetran_syncedallow_channelbackassignee_idbrand_idcreated_atdescriptiondue_atexternal_idforum_topic_id...via_channelvia_source_from_idvia_source_from_titlevia_source_relvia_source_to_addressvia_source_to_namemerged_ticket_idsvia_source_from_addressfollowup_idsvia_followup_source_id
047212020-05-14 20:12:36False3963717067733600035294742020-04-20 14:31:46Huge disappointmentNoneNoneNone...emailNoneNoneNoneexample@email.comSupport[]NoneNoneNone
166052020-06-10 02:10:24False3963153604343600035294742020-05-26 22:29:50Full display not working in all application.NoneNoneNone...emailNoneNoneNoneexample@email.comSupport[]NoneNoneNone
219662020-03-25 20:32:24False3963153604343600035294742020-02-27 06:05:08She doesn’t always listenNoneNoneNone...emailNoneNoneNoneexample@email.comSupport[1967]NoneNoneNone
3141732020-11-11 20:08:45False3963716996533600035294742020-10-28 12:03:02I sent it to my 85 year old Dad, and he talks ...NoneNoneNone...emailNoneNoneNoneexample@email.comSupport[]NoneNoneNone
414042020-03-05 04:53:46False3963716996533600035294742020-02-13 21:43:58Some major design flawsNoneNoneNone...emailNoneNoneNoneexample@email.comSupportNoneNoneNoneNone
561712020-06-01 02:11:40False3963344004943600035294742020-05-17 17:50:31nice hotel expensive parking got good deal sta...NoneNoneNone...emailNoneNoneNoneexample@email.comSupport[]NoneNoneNone
6169882021-01-13 20:09:16False4182841319343600035294742020-12-22 00:19:23Love it! I’ve listened to songs I haven’t hear...NoneNoneNone...emailNoneNoneNoneexample@email.comSupport[]None[]None
715952020-03-20 02:32:49FalseNone3600035294742020-02-19 01:54:52I think this is the 5th one I've purchased. I'...NoneNoneNone...webNoneNoneNoneexample@email.comNone[]NoneNoneNone
8110712020-10-02 14:08:33FalseNone3600035294742020-08-28 18:06:36I love it, wife hates it.NoneNoneNone...emailNoneNoneNoneXSupport[]NoneNoneNone
9110132020-10-02 20:08:20False4028516973933600035294742020-08-27 23:09:52I was a little nervous when I received my new ...NoneNoneNone...emailNoneNoneNoneXSupport[]NoneNoneNone
\n", 449 | "

10 rows × 36 columns

\n", 450 | "
" 451 | ], 452 | "text/plain": [ 453 | " id _fivetran_synced allow_channelback assignee_id brand_id \\\n", 454 | "0 4721 2020-05-14 20:12:36 False 396371706773 360003529474 \n", 455 | "1 6605 2020-06-10 02:10:24 False 396315360434 360003529474 \n", 456 | "2 1966 2020-03-25 20:32:24 False 396315360434 360003529474 \n", 457 | "3 14173 2020-11-11 20:08:45 False 396371699653 360003529474 \n", 458 | "4 1404 2020-03-05 04:53:46 False 396371699653 360003529474 \n", 459 | "5 6171 2020-06-01 02:11:40 False 396334400494 360003529474 \n", 460 | "6 16988 2021-01-13 20:09:16 False 418284131934 360003529474 \n", 461 | "7 1595 2020-03-20 02:32:49 False None 360003529474 \n", 462 | "8 11071 2020-10-02 14:08:33 False None 360003529474 \n", 463 | "9 11013 2020-10-02 20:08:20 False 402851697393 360003529474 \n", 464 | "\n", 465 | " created_at description \\\n", 466 | "0 2020-04-20 14:31:46 Huge disappointment \n", 467 | "1 2020-05-26 22:29:50 Full display not working in all application. \n", 468 | "2 2020-02-27 06:05:08 She doesn’t always listen \n", 469 | "3 2020-10-28 12:03:02 I sent it to my 85 year old Dad, and he talks ... \n", 470 | "4 2020-02-13 21:43:58 Some major design flaws \n", 471 | "5 2020-05-17 17:50:31 nice hotel expensive parking got good deal sta... \n", 472 | "6 2020-12-22 00:19:23 Love it! I’ve listened to songs I haven’t hear... \n", 473 | "7 2020-02-19 01:54:52 I think this is the 5th one I've purchased. I'... \n", 474 | "8 2020-08-28 18:06:36 I love it, wife hates it. \n", 475 | "9 2020-08-27 23:09:52 I was a little nervous when I received my new ... \n", 476 | "\n", 477 | " due_at external_id forum_topic_id ... via_channel via_source_from_id \\\n", 478 | "0 None None None ... email None \n", 479 | "1 None None None ... email None \n", 480 | "2 None None None ... email None \n", 481 | "3 None None None ... email None \n", 482 | "4 None None None ... email None \n", 483 | "5 None None None ... email None \n", 484 | "6 None None None ... email None \n", 485 | "7 None None None ... web None \n", 486 | "8 None None None ... email None \n", 487 | "9 None None None ... email None \n", 488 | "\n", 489 | " via_source_from_title via_source_rel via_source_to_address \\\n", 490 | "0 None None example@email.com \n", 491 | "1 None None example@email.com \n", 492 | "2 None None example@email.com \n", 493 | "3 None None example@email.com \n", 494 | "4 None None example@email.com \n", 495 | "5 None None example@email.com \n", 496 | "6 None None example@email.com \n", 497 | "7 None None example@email.com \n", 498 | "8 None None X \n", 499 | "9 None None X \n", 500 | "\n", 501 | " via_source_to_name merged_ticket_ids via_source_from_address followup_ids \\\n", 502 | "0 Support [] None None \n", 503 | "1 Support [] None None \n", 504 | "2 Support [1967] None None \n", 505 | "3 Support [] None None \n", 506 | "4 Support None None None \n", 507 | "5 Support [] None None \n", 508 | "6 Support [] None [] \n", 509 | "7 None [] None None \n", 510 | "8 Support [] None None \n", 511 | "9 Support [] None None \n", 512 | "\n", 513 | " via_followup_source_id \n", 514 | "0 None \n", 515 | "1 None \n", 516 | "2 None \n", 517 | "3 None \n", 518 | "4 None \n", 519 | "5 None \n", 520 | "6 None \n", 521 | "7 None \n", 522 | "8 None \n", 523 | "9 None \n", 524 | "\n", 525 | "[10 rows x 36 columns]" 526 | ] 527 | }, 528 | "execution_count": 46, 529 | "metadata": {}, 530 | "output_type": "execute_result" 531 | } 532 | ], 533 | "source": [ 534 | "tickets = faldbt.ref('stg_zendesk_ticket_data')\n", 535 | "tickets" 536 | ] 537 | }, 538 | { 539 | "cell_type": "code", 540 | "execution_count": 60, 541 | "metadata": {}, 542 | "outputs": [ 543 | { 544 | "data": { 545 | "text/html": [ 546 | "
\n", 547 | "\n", 560 | "\n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | " \n", 577 | " \n", 578 | " \n", 579 | " \n", 580 | " \n", 581 | " \n", 582 | " \n", 583 | " \n", 584 | " \n", 585 | " \n", 586 | " \n", 587 | " \n", 588 | " \n", 589 | " \n", 590 | " \n", 591 | " \n", 592 | " \n", 593 | " \n", 594 | " \n", 595 | " \n", 596 | " \n", 597 | " \n", 598 | " \n", 599 | " \n", 600 | " \n", 601 | " \n", 602 | " \n", 603 | " \n", 604 | " \n", 605 | " \n", 606 | " \n", 607 | " \n", 608 | " \n", 609 | " \n", 610 | " \n", 611 | " \n", 612 | " \n", 613 | " \n", 614 | " \n", 615 | " \n", 616 | " \n", 617 | " \n", 618 | " \n", 619 | " \n", 620 | " \n", 621 | " \n", 622 | " \n", 623 | " \n", 624 | " \n", 625 | " \n", 626 | " \n", 627 | " \n", 628 | " \n", 629 | " \n", 630 | " \n", 631 | " \n", 632 | " \n", 633 | " \n", 634 | " \n", 635 | " \n", 636 | " \n", 637 | " \n", 638 | " \n", 639 | " \n", 640 | " \n", 641 | " \n", 642 | " \n", 643 | " \n", 644 | " \n", 645 | " \n", 646 | " \n", 647 | " \n", 648 | " \n", 649 | " \n", 650 | " \n", 651 | " \n", 652 | " \n", 653 | " \n", 654 | " \n", 655 | " \n", 656 | " \n", 657 | " \n", 658 | " \n", 659 | " \n", 660 | " \n", 661 | " \n", 662 | " \n", 663 | " \n", 664 | " \n", 665 | " \n", 666 | " \n", 667 | " \n", 668 | " \n", 669 | " \n", 670 | " \n", 671 | " \n", 672 | " \n", 673 | " \n", 674 | " \n", 675 | " \n", 676 | " \n", 677 | " \n", 678 | " \n", 679 | " \n", 680 | " \n", 681 | " \n", 682 | " \n", 683 | " \n", 684 | " \n", 685 | " \n", 686 | " \n", 687 | " \n", 688 | " \n", 689 | " \n", 690 | " \n", 691 | " \n", 692 | " \n", 693 | " \n", 694 | " \n", 695 | " \n", 696 | " \n", 697 | " \n", 698 | " \n", 699 | " \n", 700 | " \n", 701 | " \n", 702 | " \n", 703 | " \n", 704 | " \n", 705 | " \n", 706 | " \n", 707 | " \n", 708 | " \n", 709 | " \n", 710 | " \n", 711 | " \n", 712 | " \n", 713 | " \n", 714 | " \n", 715 | " \n", 716 | " \n", 717 | " \n", 718 | " \n", 719 | " \n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | " \n", 735 | " \n", 736 | " \n", 737 | " \n", 738 | " \n", 739 | " \n", 740 | " \n", 741 | " \n", 742 | " \n", 743 | " \n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | " \n", 752 | " \n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " \n", 759 | " \n", 760 | " \n", 761 | " \n", 762 | " \n", 763 | " \n", 764 | " \n", 765 | " \n", 766 | " \n", 767 | " \n", 768 | " \n", 769 | " \n", 770 | " \n", 771 | " \n", 772 | " \n", 773 | " \n", 774 | " \n", 775 | " \n", 776 | " \n", 777 | " \n", 778 | " \n", 779 | " \n", 780 | " \n", 781 | " \n", 782 | " \n", 783 | " \n", 784 | " \n", 785 | " \n", 786 | " \n", 787 | " \n", 788 | " \n", 789 | " \n", 790 | " \n", 791 | " \n", 792 | " \n", 793 | " \n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 802 | " \n", 803 | " \n", 804 | " \n", 805 | " \n", 806 | " \n", 807 | " \n", 808 | " \n", 809 | " \n", 810 | " \n", 811 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | " \n", 816 | " \n", 817 | " \n", 818 | " \n", 819 | " \n", 820 | " \n", 821 | " \n", 822 | " \n", 823 | " \n", 824 | " \n", 825 | " \n", 826 | " \n", 827 | " \n", 828 | " \n", 829 | "
idlabelscore_fivetran_syncedallow_channelbackassignee_idbrand_idcreated_atdescriptiondue_at...via_source_from_idvia_source_from_titlevia_source_relvia_source_to_addressvia_source_to_namemerged_ticket_idsvia_source_from_addressfollowup_idsvia_followup_source_idweighted_label
011013NEGATIVE0.86799371242523192020-10-02 20:08:20False4028516973933600035294742020-08-27 23:09:52I was a little nervous when I received my new ...None...NoneNoneNoneXSupport[]NoneNoneNone-0.867994
16171POSITIVE0.99871790409088132020-06-01 02:11:40False3963344004943600035294742020-05-17 17:50:31nice hotel expensive parking got good deal sta...None...NoneNoneNoneexample@email.comSupport[]NoneNoneNone0.998718
21595POSITIVE0.95671790838241582020-03-20 02:32:49FalseNone3600035294742020-02-19 01:54:52I think this is the 5th one I've purchased. I'...None...NoneNoneNoneexample@email.comNone[]NoneNoneNone0.956718
311071POSITIVE0.99493861198425292020-10-02 14:08:33FalseNone3600035294742020-08-28 18:06:36I love it, wife hates it.None...NoneNoneNoneXSupport[]NoneNoneNone0.994939
416988POSITIVE0.99987578392028812021-01-13 20:09:16False4182841319343600035294742020-12-22 00:19:23Love it! I’ve listened to songs I haven’t hear...None...NoneNoneNoneexample@email.comSupport[]None[]None0.999876
514173POSITIVE0.99952721595764162020-11-11 20:08:45False3963716996533600035294742020-10-28 12:03:02I sent it to my 85 year old Dad, and he talks ...None...NoneNoneNoneexample@email.comSupport[]NoneNoneNone0.999527
64721NEGATIVE0.99980050325393682020-05-14 20:12:36False3963717067733600035294742020-04-20 14:31:46Huge disappointmentNone...NoneNoneNoneexample@email.comSupport[]NoneNoneNone-0.999801
71404NEGATIVE0.99947553873062132020-03-05 04:53:46False3963716996533600035294742020-02-13 21:43:58Some major design flawsNone...NoneNoneNoneexample@email.comSupportNoneNoneNoneNone-0.999476
81966NEGATIVE0.99229335784912112020-03-25 20:32:24False3963153604343600035294742020-02-27 06:05:08She doesn’t always listenNone...NoneNoneNoneexample@email.comSupport[1967]NoneNoneNone-0.992293
96605NEGATIVE0.99951100349426272020-06-10 02:10:24False3963153604343600035294742020-05-26 22:29:50Full display not working in all application.None...NoneNoneNoneexample@email.comSupport[]NoneNoneNone-0.999511
\n", 830 | "

10 rows × 39 columns

\n", 831 | "
" 832 | ], 833 | "text/plain": [ 834 | " id label score _fivetran_synced allow_channelback \\\n", 835 | "0 11013 NEGATIVE 0.8679937124252319 2020-10-02 20:08:20 False \n", 836 | "1 6171 POSITIVE 0.9987179040908813 2020-06-01 02:11:40 False \n", 837 | "2 1595 POSITIVE 0.9567179083824158 2020-03-20 02:32:49 False \n", 838 | "3 11071 POSITIVE 0.9949386119842529 2020-10-02 14:08:33 False \n", 839 | "4 16988 POSITIVE 0.9998757839202881 2021-01-13 20:09:16 False \n", 840 | "5 14173 POSITIVE 0.9995272159576416 2020-11-11 20:08:45 False \n", 841 | "6 4721 NEGATIVE 0.9998005032539368 2020-05-14 20:12:36 False \n", 842 | "7 1404 NEGATIVE 0.9994755387306213 2020-03-05 04:53:46 False \n", 843 | "8 1966 NEGATIVE 0.9922933578491211 2020-03-25 20:32:24 False \n", 844 | "9 6605 NEGATIVE 0.9995110034942627 2020-06-10 02:10:24 False \n", 845 | "\n", 846 | " assignee_id brand_id created_at \\\n", 847 | "0 402851697393 360003529474 2020-08-27 23:09:52 \n", 848 | "1 396334400494 360003529474 2020-05-17 17:50:31 \n", 849 | "2 None 360003529474 2020-02-19 01:54:52 \n", 850 | "3 None 360003529474 2020-08-28 18:06:36 \n", 851 | "4 418284131934 360003529474 2020-12-22 00:19:23 \n", 852 | "5 396371699653 360003529474 2020-10-28 12:03:02 \n", 853 | "6 396371706773 360003529474 2020-04-20 14:31:46 \n", 854 | "7 396371699653 360003529474 2020-02-13 21:43:58 \n", 855 | "8 396315360434 360003529474 2020-02-27 06:05:08 \n", 856 | "9 396315360434 360003529474 2020-05-26 22:29:50 \n", 857 | "\n", 858 | " description due_at ... \\\n", 859 | "0 I was a little nervous when I received my new ... None ... \n", 860 | "1 nice hotel expensive parking got good deal sta... None ... \n", 861 | "2 I think this is the 5th one I've purchased. I'... None ... \n", 862 | "3 I love it, wife hates it. None ... \n", 863 | "4 Love it! I’ve listened to songs I haven’t hear... None ... \n", 864 | "5 I sent it to my 85 year old Dad, and he talks ... None ... \n", 865 | "6 Huge disappointment None ... \n", 866 | "7 Some major design flaws None ... \n", 867 | "8 She doesn’t always listen None ... \n", 868 | "9 Full display not working in all application. None ... \n", 869 | "\n", 870 | " via_source_from_id via_source_from_title via_source_rel \\\n", 871 | "0 None None None \n", 872 | "1 None None None \n", 873 | "2 None None None \n", 874 | "3 None None None \n", 875 | "4 None None None \n", 876 | "5 None None None \n", 877 | "6 None None None \n", 878 | "7 None None None \n", 879 | "8 None None None \n", 880 | "9 None None None \n", 881 | "\n", 882 | " via_source_to_address via_source_to_name merged_ticket_ids \\\n", 883 | "0 X Support [] \n", 884 | "1 example@email.com Support [] \n", 885 | "2 example@email.com None [] \n", 886 | "3 X Support [] \n", 887 | "4 example@email.com Support [] \n", 888 | "5 example@email.com Support [] \n", 889 | "6 example@email.com Support [] \n", 890 | "7 example@email.com Support None \n", 891 | "8 example@email.com Support [1967] \n", 892 | "9 example@email.com Support [] \n", 893 | "\n", 894 | " via_source_from_address followup_ids via_followup_source_id weighted_label \n", 895 | "0 None None None -0.867994 \n", 896 | "1 None None None 0.998718 \n", 897 | "2 None None None 0.956718 \n", 898 | "3 None None None 0.994939 \n", 899 | "4 None [] None 0.999876 \n", 900 | "5 None None None 0.999527 \n", 901 | "6 None None None -0.999801 \n", 902 | "7 None None None -0.999476 \n", 903 | "8 None None None -0.992293 \n", 904 | "9 None None None -0.999511 \n", 905 | "\n", 906 | "[10 rows x 39 columns]" 907 | ] 908 | }, 909 | "execution_count": 60, 910 | "metadata": {}, 911 | "output_type": "execute_result" 912 | } 913 | ], 914 | "source": [ 915 | "import pandas as pd\n", 916 | "\n", 917 | "def calc_weighted_label(row):\n", 918 | " val = 1 if row['label'] == 'POSITIVE' else -1\n", 919 | " return val * row['score']\n", 920 | "\n", 921 | "joined = sentiments.merge(tickets, on='id')\n", 922 | "joined['weighted_label'] = joined.apply(calc_weighted_label, axis=1).astype(float)\n", 923 | "joined" 924 | ] 925 | }, 926 | { 927 | "cell_type": "code", 928 | "execution_count": 61, 929 | "metadata": {}, 930 | "outputs": [ 931 | { 932 | "data": { 933 | "image/png": "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", 934 | "text/plain": [ 935 | "
" 936 | ] 937 | }, 938 | "metadata": { 939 | "needs_background": "light" 940 | }, 941 | "output_type": "display_data" 942 | } 943 | ], 944 | "source": [ 945 | "from matplotlib import pyplot as plt\n", 946 | "\n", 947 | "\n", 948 | "joined.plot(y=['weighted_label'], x='created_at')\n", 949 | "plt.show()\n" 950 | ] 951 | } 952 | ], 953 | "metadata": { 954 | "interpreter": { 955 | "hash": "b3ae1a2afbc722729cc76efe577b0195730de2dd9e6bacdc785767fdea12b05b" 956 | }, 957 | "kernelspec": { 958 | "display_name": "Python 3.8.9 64-bit ('fal-BEX8YHmg-py3.8': poetry)", 959 | "language": "python", 960 | "name": "python3" 961 | }, 962 | "language_info": { 963 | "codemirror_mode": { 964 | "name": "ipython", 965 | "version": 3 966 | }, 967 | "file_extension": ".py", 968 | "mimetype": "text/x-python", 969 | "name": "python", 970 | "nbconvert_exporter": "python", 971 | "pygments_lexer": "ipython3", 972 | "version": "3.8.9" 973 | }, 974 | "orig_nbformat": 4 975 | }, 976 | "nbformat": 4, 977 | "nbformat_minor": 2 978 | } 979 | -------------------------------------------------------------------------------- /data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/data/.gitkeep -------------------------------------------------------------------------------- /data/raw_o3_values.csv: -------------------------------------------------------------------------------- 1 | ,O3,state,county,month,geom 2 | 0,0.044,Alaska,Denali ,2017-12-01, 3 | 1,0.044,Alaska,Denali ,2018-11-01, 4 | 2,0.036,Alaska,Denali ,2019-09-01, 5 | 3,0.042,Alaska,Denali ,2017-09-01, 6 | 4,0.046,Alaska,Denali ,2019-06-01, 7 | 5,0.044,Alaska,Denali ,2019-07-01, 8 | 6,0.03,Alaska,Denali ,2016-08-01, 9 | 7,0.052,Alaska,Denali ,2019-02-01, 10 | 8,0.041,Alaska,Denali ,2019-10-01, 11 | 9,0.032,Alaska,Denali ,2018-08-01, 12 | 10,0.04,Alaska,Denali ,2017-10-01, 13 | 11,0.056,Alaska,Denali ,2016-03-01, 14 | 12,0.047,Alaska,Denali ,2019-12-01, 15 | 13,0.048,Alaska,Denali ,2016-10-01, 16 | 14,0.054,Alaska,Denali ,2019-04-01, 17 | 15,0.05,Alaska,Denali ,2017-03-01, 18 | 16,0.049,Alaska,Denali ,2017-05-01, 19 | 17,0.036,Alaska,Denali ,2019-08-01, 20 | 18,0.056,Alaska,Denali ,2019-03-01, 21 | 19,0.037,Alaska,Denali ,2018-07-01, 22 | 20,0.042,Alaska,Denali ,2018-12-01, 23 | 21,0.053,Alaska,Denali ,2019-05-01, 24 | 22,0.057,Alaska,Denali ,2018-04-01, 25 | 23,0.045,Alaska,Denali ,2017-01-01, 26 | 24,0.045,Alaska,Denali ,2018-06-01, 27 | 25,0.053,Alaska,Denali ,2018-03-01, 28 | 26,0.053,Alaska,Denali ,2017-04-01, 29 | 27,0.047,Alaska,Denali ,2016-01-01, 30 | 28,0.05,Alaska,Denali ,2018-02-01, 31 | 29,0.04,Alaska,Denali ,2016-11-01, 32 | 30,0.038,Alaska,Denali ,2017-06-01, 33 | 31,0.043,Alaska,Denali ,2018-09-01, 34 | 32,0.044,Alaska,Denali ,2016-06-01, 35 | 33,0.047,Alaska,Denali ,2017-02-01, 36 | 34,0.033,Alaska,Denali ,2017-08-01, 37 | 35,0.048,Alaska,Denali ,2018-10-01, 38 | 36,0.042,Alaska,Denali ,2016-12-01, 39 | 37,0.031,Alaska,Denali ,2016-07-01, 40 | 38,0.045,Alaska,Denali ,2016-02-01, 41 | 39,0.045,Alaska,Denali ,2016-05-01, 42 | 40,0.043,Alaska,Denali ,2018-01-01, 43 | 41,0.045,Alaska,Denali ,2019-01-01, 44 | 42,0.043,Alaska,Denali ,2019-11-01, 45 | 43,0.042,Alaska,Denali ,2017-11-01, 46 | 44,0.05,Alaska,Denali ,2016-04-01, 47 | 45,0.055,Alaska,Denali ,2018-05-01, 48 | 46,0.03,Alaska,Matanuska-Susitna ,2018-06-01, 49 | 47,0.042,Alaska,Matanuska-Susitna ,2017-03-01, 50 | 48,0.036,Alaska,Matanuska-Susitna ,2018-05-01, 51 | 49,0.028,Alaska,Matanuska-Susitna ,2016-08-01, 52 | 50,0.029,Alaska,Matanuska-Susitna ,2017-08-01, 53 | 51,0.04,Alaska,Matanuska-Susitna ,2016-01-01, 54 | 52,0.037,Alaska,Matanuska-Susitna ,2018-02-01, 55 | 53,0.033,Alaska,Matanuska-Susitna ,2018-01-01, 56 | 54,0.032,Alaska,Matanuska-Susitna ,2016-09-01, 57 | 55,0.051,Alaska,Matanuska-Susitna ,2018-03-01, 58 | 56,0.03,Alaska,Matanuska-Susitna ,2017-09-01, 59 | 57,0.046,Alaska,Matanuska-Susitna ,2017-04-01, 60 | 58,0.037,Alaska,Matanuska-Susitna ,2017-06-01, 61 | 59,0.021,Alaska,Matanuska-Susitna ,2018-08-01, 62 | 60,0.027,Alaska,Matanuska-Susitna ,2017-07-01, 63 | 61,0.029,Alaska,Matanuska-Susitna ,2018-11-01, 64 | 62,0.032,Alaska,Matanuska-Susitna ,2016-11-01, 65 | 63,0.04,Alaska,Matanuska-Susitna ,2017-02-01, 66 | 64,0.043,Alaska,Matanuska-Susitna ,2017-05-01, 67 | 65,0.036,Alaska,Matanuska-Susitna ,2016-06-01, 68 | 66,0.041,Alaska,Matanuska-Susitna ,2016-02-01, 69 | 67,0.026,Alaska,Matanuska-Susitna ,2018-07-01, 70 | 68,0.035,Alaska,Matanuska-Susitna ,2017-10-01, 71 | 69,0.044,Alaska,Matanuska-Susitna ,2016-05-01, 72 | 70,0.044,Alaska,Matanuska-Susitna ,2016-03-01, 73 | 71,0.044,Alaska,Matanuska-Susitna ,2018-04-01, 74 | 72,0.037,Alaska,Matanuska-Susitna ,2016-10-01, 75 | 73,0.034,Alaska,Matanuska-Susitna ,2016-12-01, 76 | 74,0.027,Alaska,Matanuska-Susitna ,2018-09-01, 77 | 75,0.032,Alaska,Matanuska-Susitna ,2018-10-01, 78 | 76,0.033,Alaska,Matanuska-Susitna ,2016-07-01, 79 | 77,0.038,Alaska,Matanuska-Susitna ,2017-01-01, 80 | 78,0.045,Alaska,Matanuska-Susitna ,2016-04-01, 81 | 79,0.04,Alaska,Fairbanks North Star ,2018-07-01, 82 | 80,0.05,Alaska,Fairbanks North Star ,2017-04-01, 83 | 81,0.036,Alaska,Fairbanks North Star ,2019-11-01, 84 | 82,0.023,Alaska,Fairbanks North Star ,2019-02-01, 85 | 83,0.047,Alaska,Fairbanks North Star ,2019-05-01, 86 | 84,0.042,Alaska,Fairbanks North Star ,2016-06-01, 87 | 85,0.029,Alaska,Fairbanks North Star ,2018-12-01, 88 | 86,0.03,Alaska,Fairbanks North Star ,2017-11-01, 89 | 87,0.036,Alaska,Fairbanks North Star ,2016-05-01, 90 | 88,0.032,Alaska,Fairbanks North Star ,2016-09-01, 91 | 89,0.037,Alaska,Fairbanks North Star ,2018-02-01, 92 | 90,0.023,Alaska,Fairbanks North Star ,2018-11-01, 93 | 91,0.04,Alaska,Fairbanks North Star ,2019-06-01, 94 | 92,0.031,Alaska,Fairbanks North Star ,2019-12-01, 95 | 93,0.035,Alaska,Fairbanks North Star ,2017-09-01, 96 | 94,0.045,Alaska,Fairbanks North Star ,2018-04-01, 97 | 95,0.036,Alaska,Fairbanks North Star ,2016-04-01, 98 | 96,0.039,Alaska,Fairbanks North Star ,2019-07-01, 99 | 97,0.029,Alaska,Fairbanks North Star ,2016-02-01, 100 | 98,0.019,Alaska,Fairbanks North Star ,2017-02-01, 101 | 99,0.036,Alaska,Fairbanks North Star ,2018-03-01, 102 | 100,0.048,Alaska,Fairbanks North Star ,2019-04-01, 103 | 101,0.033,Alaska,Fairbanks North Star ,2019-08-01, 104 | 102,0.035,Alaska,Fairbanks North Star ,2018-01-01, 105 | 103,0.029,Alaska,Fairbanks North Star ,2019-10-01, 106 | 104,0.044,Alaska,Fairbanks North Star ,2019-03-01, 107 | 105,0.036,Alaska,Fairbanks North Star ,2018-10-01, 108 | 106,0.03,Alaska,Fairbanks North Star ,2017-10-01, 109 | 107,0.049,Alaska,Fairbanks North Star ,2017-05-01, 110 | 108,0.029,Alaska,Fairbanks North Star ,2019-09-01, 111 | 109,0.038,Alaska,Fairbanks North Star ,2017-12-01, 112 | 110,0.04,Alaska,Fairbanks North Star ,2017-06-01, 113 | 111,0.035,Alaska,Fairbanks North Star ,2017-08-01, 114 | 112,0.027,Alaska,Fairbanks North Star ,2018-08-01, 115 | 113,0.041,Alaska,Fairbanks North Star ,2018-05-01, 116 | 114,0.031,Alaska,Fairbanks North Star ,2016-08-01, 117 | 115,0.026,Alaska,Fairbanks North Star ,2016-01-01, 118 | 116,0.035,Alaska,Fairbanks North Star ,2016-10-01, 119 | 117,0.03,Alaska,Fairbanks North Star ,2017-01-01, 120 | 118,0.043,Alaska,Fairbanks North Star ,2017-07-01, 121 | 119,0.03,Alaska,Fairbanks North Star ,2018-09-01, 122 | 120,0.036,Alaska,Fairbanks North Star ,2018-06-01, 123 | 121,0.023,Alaska,Fairbanks North Star ,2019-01-01, 124 | 122,0.026,Alaska,Fairbanks North Star ,2016-03-01, 125 | 123,0.038,Alaska,Fairbanks North Star ,2016-07-01, 126 | 124,0.062,Alabama,Tuscaloosa,2016-09-01, 127 | 125,0.054,Alabama,Tuscaloosa,2018-09-01, 128 | 126,0.066,Alabama,Tuscaloosa,2019-09-01, 129 | 127,0.054,Alabama,Tuscaloosa,2018-03-01, 130 | 128,0.049,Alabama,Tuscaloosa,2019-05-01, 131 | 129,0.053,Alabama,Tuscaloosa,2017-06-01, 132 | 130,0.062,Alabama,Tuscaloosa,2019-08-01, 133 | 131,0.075,Alabama,Tuscaloosa,2018-06-01, 134 | 132,0.059,Alabama,Tuscaloosa,2019-10-01, 135 | 133,0.065,Alabama,Tuscaloosa,2016-07-01, 136 | 134,0.051,Alabama,Tuscaloosa,2016-08-01, 137 | 135,0.057,Alabama,Tuscaloosa,2017-04-01, 138 | 136,0.044,Alabama,Tuscaloosa,2018-10-01, 139 | 137,0.065,Alabama,Tuscaloosa,2017-05-01, 140 | 138,0.057,Alabama,Tuscaloosa,2019-06-01, 141 | 139,0.059,Alabama,Tuscaloosa,2016-05-01, 142 | 140,0.063,Alabama,Tuscaloosa,2018-07-01, 143 | 141,0.057,Alabama,Tuscaloosa,2016-04-01, 144 | 142,0.053,Alabama,Tuscaloosa,2016-03-01, 145 | 143,0.059,Alabama,Tuscaloosa,2018-04-01, 146 | 144,0.06,Alabama,Tuscaloosa,2017-09-01, 147 | 145,0.053,Alabama,Tuscaloosa,2019-04-01, 148 | 146,0.07,Alabama,Tuscaloosa,2016-06-01, 149 | 147,0.051,Alabama,Tuscaloosa,2017-10-01, 150 | 148,0.058,Alabama,Tuscaloosa,2016-10-01, 151 | 149,0.056,Alabama,Tuscaloosa,2018-08-01, 152 | 150,0.052,Alabama,Tuscaloosa,2017-07-01, 153 | 151,0.058,Alabama,Tuscaloosa,2017-08-01, 154 | 152,0.054,Alabama,Tuscaloosa,2017-03-01, 155 | 153,0.054,Alabama,Tuscaloosa,2019-07-01, 156 | 154,0.063,Alabama,Tuscaloosa,2018-05-01, 157 | 155,0.072,Arizona,La Paz,2017-06-01, 158 | 156,0.055,Arizona,La Paz,2017-10-01, 159 | 157,0.044,Arizona,La Paz,2018-12-01, 160 | 158,0.05,Arizona,La Paz,2016-11-01, 161 | 159,0.061,Arizona,La Paz,2019-04-01, 162 | 160,0.053,Arizona,La Paz,2016-08-01, 163 | 161,0.058,Arizona,La Paz,2019-10-01, 164 | 162,0.069,Arizona,La Paz,2016-07-01, 165 | 163,0.043,Arizona,La Paz,2019-12-01, 166 | 164,0.071,Arizona,La Paz,2018-05-01, 167 | 165,0.062,Arizona,La Paz,2019-03-01, 168 | 166,0.068,Arizona,La Paz,2016-05-01, 169 | 167,0.072,Arizona,La Paz,2018-04-01, 170 | 168,0.054,Arizona,La Paz,2019-08-01, 171 | 169,0.047,Arizona,La Paz,2018-01-01, 172 | 170,0.048,Arizona,La Paz,2019-01-01, 173 | 171,0.062,Arizona,La Paz,2018-08-01, 174 | 172,0.044,Arizona,La Paz,2016-12-01, 175 | 173,0.049,Arizona,La Paz,2017-12-01, 176 | 174,0.054,Arizona,La Paz,2016-09-01, 177 | 175,0.067,Arizona,La Paz,2018-06-01, 178 | 176,0.064,Arizona,La Paz,2016-06-01, 179 | 177,0.06,Arizona,La Paz,2018-03-01, 180 | 178,0.05,Arizona,La Paz,2017-11-01, 181 | 179,0.06,Arizona,La Paz,2016-03-01, 182 | 180,0.062,Arizona,La Paz,2017-07-01, 183 | 181,0.062,Arizona,La Paz,2019-05-01, 184 | 182,0.067,Arizona,La Paz,2017-05-01, 185 | 183,0.052,Arizona,La Paz,2017-02-01, 186 | 184,0.059,Arizona,La Paz,2017-03-01, 187 | 185,0.057,Arizona,La Paz,2018-09-01, 188 | 186,0.052,Arizona,La Paz,2019-02-01, 189 | 187,0.069,Arizona,La Paz,2017-04-01, 190 | 188,0.055,Arizona,La Paz,2016-02-01, 191 | 189,0.047,Arizona,La Paz,2017-01-01, 192 | 190,0.052,Arizona,La Paz,2019-11-01, 193 | 191,0.07,Arizona,La Paz,2018-07-01, 194 | 192,0.05,Arizona,La Paz,2018-11-01, 195 | 193,0.06,Arizona,La Paz,2019-09-01, 196 | 194,0.063,Arizona,La Paz,2019-06-01, 197 | 195,0.061,Arizona,La Paz,2017-09-01, 198 | 196,0.057,Arizona,La Paz,2017-08-01, 199 | 197,0.071,Arizona,La Paz,2016-04-01, 200 | 198,0.054,Arizona,La Paz,2018-02-01, 201 | 199,0.063,Arizona,La Paz,2019-07-01, 202 | 200,0.055,Arizona,La Paz,2018-10-01, 203 | 201,0.048,Arizona,La Paz,2016-01-01, 204 | 202,0.072,Florida,Polk,2017-03-01, 205 | 203,0.045,Florida,Polk,2016-08-01, 206 | 204,0.067,Florida,Polk,2016-05-01, 207 | 205,0.049,Florida,Polk,2017-07-01, 208 | 206,0.042,Florida,Polk,2018-12-01, 209 | 207,0.061,Florida,Polk,2019-05-01, 210 | 208,0.062,Florida,Polk,2019-09-01, 211 | 209,0.059,Florida,Polk,2016-02-01, 212 | 210,0.052,Florida,Polk,2017-11-01, 213 | 211,0.064,Florida,Polk,2019-06-01, 214 | 212,0.048,Florida,Polk,2016-01-01, 215 | 213,0.042,Florida,Polk,2018-11-01, 216 | 214,0.057,Florida,Polk,2019-02-01, 217 | 215,0.048,Florida,Polk,2017-01-01, 218 | 216,0.046,Florida,Polk,2019-12-01, 219 | 217,0.083,Florida,Polk,2017-05-01, 220 | 218,0.065,Florida,Polk,2016-03-01, 221 | 219,0.068,Florida,Polk,2017-04-01, 222 | 220,0.045,Florida,Polk,2016-12-01, 223 | 221,0.06,Florida,Polk,2016-06-01, 224 | 222,0.046,Florida,Polk,2019-11-01, 225 | 223,0.052,Florida,Polk,2017-09-01, 226 | 224,0.047,Florida,Polk,2019-01-01, 227 | 225,0.065,Florida,Polk,2018-03-01, 228 | 226,0.074,Florida,Polk,2018-04-01, 229 | 227,0.039,Florida,Polk,2019-08-01, 230 | 228,0.046,Florida,Polk,2018-09-01, 231 | 229,0.049,Florida,Polk,2018-01-01, 232 | 230,0.06,Florida,Polk,2018-10-01, 233 | 231,0.047,Florida,Polk,2017-08-01, 234 | 232,0.055,Florida,Polk,2016-09-01, 235 | 233,0.056,Florida,Polk,2017-06-01, 236 | 234,0.058,Florida,Polk,2017-02-01, 237 | 235,0.039,Florida,Polk,2018-08-01, 238 | 236,0.048,Florida,Polk,2017-12-01, 239 | 237,0.047,Florida,Polk,2018-02-01, 240 | 238,0.068,Florida,Polk,2019-03-01, 241 | 239,0.049,Florida,Polk,2019-07-01, 242 | 240,0.055,Florida,Polk,2018-06-01, 243 | 241,0.048,Florida,Polk,2016-07-01, 244 | 242,0.05,Florida,Polk,2017-10-01, 245 | 243,0.053,Florida,Polk,2019-10-01, 246 | 244,0.054,Florida,Polk,2016-11-01, 247 | 245,0.055,Florida,Polk,2018-07-01, 248 | 246,0.063,Florida,Polk,2016-04-01, 249 | 247,0.049,Florida,Polk,2016-10-01, 250 | 248,0.07,Florida,Polk,2019-04-01, 251 | 249,0.072,Florida,Polk,2018-05-01, 252 | 250,0.046,Florida,Volusia,2016-12-01, 253 | 251,0.047,Florida,Volusia,2019-11-01, 254 | 252,0.046,Florida,Volusia,2016-07-01, 255 | 253,0.054,Florida,Volusia,2019-06-01, 256 | 254,0.063,Florida,Volusia,2016-05-01, 257 | 255,0.05,Florida,Volusia,2017-12-01, 258 | 256,0.054,Florida,Volusia,2019-09-01, 259 | 257,0.056,Florida,Volusia,2017-02-01, 260 | 258,0.046,Florida,Volusia,2018-01-01, 261 | 259,0.055,Florida,Volusia,2018-10-01, 262 | 260,0.049,Florida,Volusia,2019-07-01, 263 | 261,0.046,Florida,Volusia,2019-12-01, 264 | 262,0.062,Florida,Volusia,2017-03-01, 265 | 263,0.063,Florida,Volusia,2018-05-01, 266 | 264,0.058,Florida,Volusia,2018-06-01, 267 | 265,0.045,Florida,Volusia,2016-09-01, 268 | 266,0.05,Florida,Volusia,2019-01-01, 269 | 267,0.065,Florida,Volusia,2017-04-01, 270 | 268,0.053,Florida,Volusia,2016-02-01, 271 | 269,0.056,Florida,Volusia,2019-04-01, 272 | 270,0.04,Florida,Volusia,2016-08-01, 273 | 271,0.064,Florida,Volusia,2018-04-01, 274 | 272,0.056,Florida,Volusia,2016-06-01, 275 | 273,0.055,Florida,Volusia,2019-05-01, 276 | 274,0.056,Florida,Volusia,2016-11-01, 277 | 275,0.068,Florida,Volusia,2017-05-01, 278 | 276,0.049,Florida,Volusia,2017-07-01, 279 | 277,0.064,Florida,Volusia,2018-03-01, 280 | 278,0.043,Florida,Volusia,2018-09-01, 281 | 279,0.049,Florida,Volusia,2017-01-01, 282 | 280,0.045,Florida,Volusia,2018-11-01, 283 | 281,0.04,Florida,Volusia,2017-08-01, 284 | 282,0.064,Florida,Volusia,2019-03-01, 285 | 283,0.051,Florida,Volusia,2017-10-01, 286 | 284,0.046,Florida,Volusia,2019-02-01, 287 | 285,0.044,Florida,Volusia,2018-08-01, 288 | 286,0.045,Florida,Volusia,2018-02-01, 289 | 287,0.045,Florida,Volusia,2019-10-01, 290 | 288,0.057,Florida,Volusia,2016-10-01, 291 | 289,0.043,Florida,Volusia,2018-12-01, 292 | 290,0.044,Florida,Volusia,2019-08-01, 293 | 291,0.05,Florida,Volusia,2017-09-01, 294 | 292,0.048,Florida,Volusia,2017-06-01, 295 | 293,0.048,Florida,Volusia,2017-11-01, 296 | 294,0.059,Florida,Volusia,2016-04-01, 297 | 295,0.054,Florida,Volusia,2016-03-01, 298 | 296,0.043,Florida,Volusia,2016-01-01, 299 | 297,0.047,Florida,Wakulla,2018-11-01, 300 | 298,0.05,Florida,Wakulla,2016-01-01, 301 | 299,0.057,Florida,Wakulla,2016-02-01, 302 | 300,0.042,Florida,Wakulla,2018-12-01, 303 | 301,0.051,Florida,Wakulla,2016-10-01, 304 | 302,0.053,Florida,Wakulla,2016-03-01, 305 | 303,0.036,Florida,Wakulla,2018-09-01, 306 | 304,0.043,Florida,Wakulla,2019-11-01, 307 | 305,0.05,Florida,Wakulla,2018-06-01, 308 | 306,0.063,Florida,Wakulla,2017-03-01, 309 | 307,0.042,Florida,Wakulla,2019-12-01, 310 | 308,0.039,Florida,Wakulla,2016-12-01, 311 | 309,0.049,Florida,Wakulla,2018-10-01, 312 | 310,0.043,Florida,Wakulla,2019-10-01, 313 | 311,0.059,Florida,Wakulla,2017-04-01, 314 | 312,0.061,Florida,Wakulla,2016-05-01, 315 | 313,0.061,Florida,Wakulla,2018-05-01, 316 | 314,0.043,Florida,Wakulla,2016-08-01, 317 | 315,0.051,Florida,Wakulla,2017-10-01, 318 | 316,0.062,Florida,Wakulla,2019-04-01, 319 | 317,0.061,Florida,Wakulla,2018-03-01, 320 | 318,0.065,Florida,Wakulla,2019-03-01, 321 | 319,0.05,Florida,Wakulla,2017-01-01, 322 | 320,0.062,Florida,Wakulla,2016-04-01, 323 | 321,0.057,Florida,Wakulla,2016-06-01, 324 | 322,0.052,Florida,Wakulla,2017-09-01, 325 | 323,0.056,Florida,Wakulla,2017-11-01, 326 | 324,0.06,Florida,Wakulla,2018-04-01, 327 | 325,0.056,Florida,Wakulla,2019-06-01, 328 | 326,0.048,Florida,Wakulla,2017-06-01, 329 | 327,0.048,Florida,Wakulla,2018-07-01, 330 | 328,0.048,Florida,Wakulla,2019-08-01, 331 | 329,0.065,Florida,Wakulla,2017-05-01, 332 | 330,0.041,Florida,Wakulla,2017-08-01, 333 | 331,0.057,Florida,Wakulla,2016-11-01, 334 | 332,0.049,Florida,Wakulla,2018-01-01, 335 | 333,0.044,Florida,Wakulla,2017-07-01, 336 | 334,0.055,Florida,Wakulla,2019-05-01, 337 | 335,0.053,Florida,Wakulla,2017-02-01, 338 | 336,0.043,Florida,Wakulla,2017-12-01, 339 | 337,0.054,Florida,Wakulla,2019-09-01, 340 | 338,0.046,Florida,Wakulla,2019-01-01, 341 | 339,0.038,Florida,Wakulla,2016-07-01, 342 | 340,0.042,Florida,Wakulla,2016-09-01, 343 | 341,0.046,Florida,Wakulla,2019-02-01, 344 | 342,0.045,Florida,Wakulla,2019-07-01, 345 | 343,0.041,Florida,Wakulla,2018-02-01, 346 | 344,0.067,Florida,Sarasota,2016-11-01, 347 | 345,0.05,Florida,Sarasota,2017-01-01, 348 | 346,0.069,Florida,Sarasota,2018-04-01, 349 | 347,0.05,Florida,Sarasota,2016-08-01, 350 | 348,0.053,Florida,Sarasota,2017-06-01, 351 | 349,0.07,Florida,Sarasota,2019-03-01, 352 | 350,0.065,Florida,Sarasota,2017-09-01, 353 | 351,0.048,Florida,Sarasota,2019-10-01, 354 | 352,0.056,Florida,Sarasota,2016-06-01, 355 | 353,0.051,Florida,Sarasota,2016-09-01, 356 | 354,0.064,Florida,Sarasota,2018-07-01, 357 | 355,0.047,Florida,Sarasota,2016-12-01, 358 | 356,0.055,Florida,Sarasota,2016-02-01, 359 | 357,0.069,Florida,Sarasota,2017-04-01, 360 | 358,0.055,Florida,Sarasota,2018-06-01, 361 | 359,0.051,Florida,Sarasota,2018-09-01, 362 | 360,0.05,Florida,Sarasota,2019-07-01, 363 | 361,0.053,Florida,Sarasota,2019-11-01, 364 | 362,0.054,Florida,Sarasota,2017-10-01, 365 | 363,0.065,Florida,Sarasota,2019-04-01, 366 | 364,0.049,Florida,Sarasota,2019-01-01, 367 | 365,0.051,Florida,Sarasota,2019-12-01, 368 | 366,0.055,Florida,Sarasota,2017-11-01, 369 | 367,0.044,Florida,Sarasota,2017-08-01, 370 | 368,0.053,Florida,Sarasota,2016-10-01, 371 | 369,0.069,Florida,Sarasota,2018-05-01, 372 | 370,0.043,Florida,Sarasota,2016-07-01, 373 | 371,0.061,Florida,Sarasota,2017-02-01, 374 | 372,0.062,Florida,Sarasota,2019-06-01, 375 | 373,0.047,Florida,Sarasota,2018-02-01, 376 | 374,0.047,Florida,Sarasota,2018-01-01, 377 | 375,0.065,Florida,Sarasota,2018-10-01, 378 | 376,0.062,Florida,Sarasota,2017-03-01, 379 | 377,0.066,Florida,Sarasota,2018-03-01, 380 | 378,0.044,Florida,Sarasota,2018-12-01, 381 | 379,0.052,Florida,Sarasota,2016-01-01, 382 | 380,0.04,Florida,Sarasota,2017-07-01, 383 | 381,0.061,Florida,Sarasota,2016-04-01, 384 | 382,0.043,Florida,Sarasota,2019-08-01, 385 | 383,0.05,Florida,Sarasota,2019-02-01, 386 | 384,0.069,Florida,Sarasota,2016-05-01, 387 | 385,0.075,Florida,Sarasota,2017-05-01, 388 | 386,0.056,Florida,Sarasota,2019-09-01, 389 | 387,0.041,Florida,Sarasota,2018-08-01, 390 | 388,0.051,Florida,Sarasota,2017-12-01, 391 | 389,0.062,Florida,Sarasota,2016-03-01, 392 | 390,0.057,Florida,Sarasota,2019-05-01, 393 | 391,0.048,Florida,Sarasota,2018-11-01, 394 | 392,0.072,Florida,Miami-Dade,2019-03-01, 395 | 393,0.047,Florida,Miami-Dade,2018-11-01, 396 | 394,0.055,Florida,Miami-Dade,2019-07-01, 397 | 395,0.057,Florida,Miami-Dade,2016-10-01, 398 | 396,0.058,Florida,Miami-Dade,2019-02-01, 399 | 397,0.041,Florida,Miami-Dade,2016-09-01, 400 | 398,0.05,Florida,Miami-Dade,2018-12-01, 401 | 399,0.054,Florida,Miami-Dade,2017-12-01, 402 | 400,0.067,Florida,Miami-Dade,2017-04-01, 403 | 401,0.048,Florida,Miami-Dade,2016-12-01, 404 | 402,0.062,Florida,Miami-Dade,2016-11-01, 405 | 403,0.057,Florida,Miami-Dade,2019-05-01, 406 | 404,0.06,Florida,Miami-Dade,2018-07-01, 407 | 405,0.054,Florida,Miami-Dade,2017-01-01, 408 | 406,0.038,Florida,Miami-Dade,2019-10-01, 409 | 407,0.054,Florida,Miami-Dade,2019-12-01, 410 | 408,0.081,Florida,Miami-Dade,2017-03-01, 411 | 409,0.054,Florida,Miami-Dade,2016-06-01, 412 | 410,0.036,Florida,Miami-Dade,2019-08-01, 413 | 411,0.046,Florida,Miami-Dade,2016-07-01, 414 | 412,0.048,Florida,Miami-Dade,2017-10-01, 415 | 413,0.057,Florida,Miami-Dade,2019-11-01, 416 | 414,0.051,Florida,Miami-Dade,2016-01-01, 417 | 415,0.053,Florida,Miami-Dade,2018-05-01, 418 | 416,0.045,Florida,Miami-Dade,2017-09-01, 419 | 417,0.048,Florida,Miami-Dade,2017-06-01, 420 | 418,0.078,Florida,Miami-Dade,2018-04-01, 421 | 419,0.045,Florida,Miami-Dade,2018-06-01, 422 | 420,0.036,Florida,Miami-Dade,2018-08-01, 423 | 421,0.06,Florida,Miami-Dade,2019-04-01, 424 | 422,0.081,Florida,Miami-Dade,2016-05-01, 425 | 423,0.072,Florida,Miami-Dade,2018-03-01, 426 | 424,0.031,Florida,Miami-Dade,2017-07-01, 427 | 425,0.035,Florida,Miami-Dade,2017-08-01, 428 | 426,0.056,Florida,Miami-Dade,2016-03-01, 429 | 427,0.037,Florida,Miami-Dade,2018-09-01, 430 | 428,0.05,Florida,Miami-Dade,2018-01-01, 431 | 429,0.057,Florida,Miami-Dade,2018-10-01, 432 | 430,0.058,Florida,Miami-Dade,2016-02-01, 433 | 431,0.043,Florida,Miami-Dade,2019-06-01, 434 | 432,0.053,Florida,Miami-Dade,2019-09-01, 435 | 433,0.05,Florida,Miami-Dade,2018-02-01, 436 | 434,0.073,Florida,Miami-Dade,2017-05-01, 437 | 435,0.054,Florida,Miami-Dade,2017-11-01, 438 | 436,0.062,Florida,Miami-Dade,2017-02-01, 439 | 437,0.065,Florida,Miami-Dade,2016-04-01, 440 | 438,0.036,Florida,Miami-Dade,2016-08-01, 441 | 439,0.053,Florida,Miami-Dade,2019-01-01, 442 | 440,0.078,Georgia,Pike,2016-06-01, 443 | 441,0.055,Georgia,Pike,2018-09-01, 444 | 442,0.062,Georgia,Pike,2018-03-01, 445 | 443,0.062,Georgia,Pike,2018-10-01, 446 | 444,0.076,Georgia,Pike,2019-09-01, 447 | 445,0.048,Georgia,Pike,2016-01-01, 448 | 446,0.058,Georgia,Pike,2017-02-01, 449 | 447,0.061,Georgia,Pike,2017-04-01, 450 | 448,0.059,Georgia,Pike,2016-03-01, 451 | 449,0.076,Georgia,Pike,2017-08-01, 452 | 450,0.061,Georgia,Pike,2016-07-01, 453 | 451,0.066,Georgia,Pike,2017-09-01, 454 | 452,0.053,Georgia,Pike,2017-01-01, 455 | 453,0.057,Georgia,Pike,2016-11-01, 456 | 454,0.045,Georgia,Pike,2018-11-01, 457 | 455,0.065,Georgia,Pike,2019-03-01, 458 | 456,0.061,Georgia,Pike,2019-04-01, 459 | 457,0.041,Georgia,Pike,2016-12-01, 460 | 458,0.046,Georgia,Pike,2017-12-01, 461 | 459,0.043,Georgia,Pike,2019-12-01, 462 | 460,0.054,Georgia,Pike,2018-08-01, 463 | 461,0.056,Georgia,Pike,2017-03-01, 464 | 462,0.06,Georgia,Pike,2017-05-01, 465 | 463,0.068,Georgia,Pike,2019-06-01, 466 | 464,0.058,Georgia,Pike,2019-07-01, 467 | 465,0.047,Georgia,Pike,2019-01-01, 468 | 466,0.045,Georgia,Pike,2018-01-01, 469 | 467,0.064,Georgia,Pike,2019-05-01, 470 | 468,0.059,Georgia,Pike,2016-08-01, 471 | 469,0.067,Georgia,Pike,2016-09-01, 472 | 470,0.074,Georgia,Pike,2016-10-01, 473 | 471,0.084,Georgia,Pike,2019-10-01, 474 | 472,0.062,Georgia,Pike,2017-07-01, 475 | 473,0.045,Georgia,Pike,2019-11-01, 476 | 474,0.044,Georgia,Pike,2019-02-01, 477 | 475,0.051,Georgia,Pike,2017-11-01, 478 | 476,0.068,Georgia,Pike,2019-08-01, 479 | 477,0.061,Georgia,Pike,2017-06-01, 480 | 478,0.063,Georgia,Pike,2016-04-01, 481 | 479,0.066,Georgia,Pike,2018-05-01, 482 | 480,0.054,Georgia,Pike,2016-02-01, 483 | 481,0.053,Georgia,Pike,2017-10-01, 484 | 482,0.075,Georgia,Pike,2018-06-01, 485 | 483,0.039,Georgia,Pike,2018-12-01, 486 | 484,0.048,Georgia,Glynn,2018-10-01, 487 | 485,0.055,Georgia,Glynn,2016-03-01, 488 | 486,0.048,Georgia,Glynn,2016-07-01, 489 | 487,0.057,Georgia,Glynn,2018-04-01, 490 | 488,0.053,Georgia,Glynn,2016-09-01, 491 | 489,0.058,Georgia,Glynn,2019-05-01, 492 | 490,0.051,Georgia,Glynn,2017-06-01, 493 | 491,0.061,Georgia,Glynn,2018-05-01, 494 | 492,0.055,Georgia,Glynn,2017-04-01, 495 | 493,0.059,Georgia,Glynn,2018-06-01, 496 | 494,0.058,Georgia,Glynn,2017-03-01, 497 | 495,0.064,Georgia,Glynn,2019-06-01, 498 | 496,0.054,Georgia,Glynn,2016-10-01, 499 | 497,0.059,Georgia,Glynn,2019-07-01, 500 | 498,0.047,Georgia,Glynn,2017-07-01, 501 | 499,0.043,Georgia,Glynn,2018-09-01, 502 | 500,0.05,Georgia,Glynn,2017-09-01, 503 | 501,0.053,Georgia,Glynn,2019-09-01, 504 | 502,0.047,Georgia,Glynn,2017-10-01, 505 | 503,0.042,Georgia,Glynn,2016-08-01, 506 | 504,0.062,Georgia,Glynn,2018-03-01, 507 | 505,0.06,Georgia,Glynn,2016-05-01, 508 | 506,0.062,Georgia,Glynn,2019-04-01, 509 | 507,0.038,Georgia,Glynn,2017-08-01, 510 | 508,0.051,Georgia,Glynn,2019-08-01, 511 | 509,0.043,Georgia,Glynn,2019-10-01, 512 | 510,0.055,Georgia,Glynn,2016-04-01, 513 | 511,0.063,Georgia,Glynn,2017-05-01, 514 | 512,0.06,Georgia,Glynn,2019-03-01, 515 | 513,0.057,Georgia,Glynn,2018-07-01, 516 | 514,0.058,Georgia,Henry,2018-03-01, 517 | 515,0.085,Georgia,Henry,2019-08-01, 518 | 516,0.075,Georgia,Henry,2018-05-01, 519 | 517,0.079,Georgia,Henry,2017-07-01, 520 | 518,0.064,Georgia,Henry,2016-10-01, 521 | 519,0.079,Georgia,Henry,2019-06-01, 522 | 520,0.063,Georgia,Henry,2018-08-01, 523 | 521,0.065,Georgia,Henry,2017-06-01, 524 | 522,0.078,Georgia,Henry,2016-05-01, 525 | 523,0.073,Georgia,Henry,2016-07-01, 526 | 524,0.072,Georgia,Henry,2018-07-01, 527 | 525,0.064,Georgia,Henry,2017-04-01, 528 | 526,0.072,Georgia,Henry,2019-09-01, 529 | 527,0.075,Georgia,Henry,2019-07-01, 530 | 528,0.065,Georgia,Henry,2016-04-01, 531 | 529,0.059,Georgia,Henry,2018-04-01, 532 | 530,0.057,Georgia,Henry,2019-04-01, 533 | 531,0.055,Georgia,Henry,2017-10-01, 534 | 532,0.065,Georgia,Henry,2017-05-01, 535 | 533,0.071,Georgia,Henry,2018-06-01, 536 | 534,0.089,Georgia,Henry,2016-06-01, 537 | 535,0.055,Georgia,Henry,2017-03-01, 538 | 536,0.055,Georgia,Henry,2016-03-01, 539 | 537,0.062,Georgia,Henry,2018-10-01, 540 | 538,0.076,Georgia,Henry,2017-08-01, 541 | 539,0.071,Georgia,Henry,2016-08-01, 542 | 540,0.052,Georgia,Henry,2018-09-01, 543 | 541,0.06,Georgia,Henry,2019-03-01, 544 | 542,0.07,Georgia,Henry,2019-10-01, 545 | 543,0.069,Georgia,Henry,2016-09-01, 546 | 544,0.065,Georgia,Henry,2017-09-01, 547 | 545,0.06,Georgia,Henry,2019-05-01, 548 | 546,0.051,Georgia,Murray,2018-08-01, 549 | 547,0.061,Georgia,Murray,2019-10-01, 550 | 548,0.062,Georgia,Murray,2019-09-01, 551 | 549,0.059,Georgia,Murray,2019-06-01, 552 | 550,0.07,Georgia,Murray,2018-04-01, 553 | 551,0.06,Georgia,Murray,2016-10-01, 554 | 552,0.066,Georgia,Murray,2017-06-01, 555 | 553,0.051,Georgia,Murray,2017-10-01, 556 | 554,0.057,Georgia,Murray,2018-07-01, 557 | 555,0.074,Georgia,Murray,2016-04-01, 558 | 556,0.056,Georgia,Murray,2017-07-01, 559 | 557,0.06,Georgia,Murray,2019-08-01, 560 | 558,0.059,Georgia,Murray,2017-03-01, 561 | 559,0.064,Georgia,Murray,2017-08-01, 562 | 560,0.067,Georgia,Murray,2018-06-01, 563 | 561,0.067,Georgia,Murray,2017-04-01, 564 | 562,0.06,Georgia,Murray,2018-03-01, 565 | 563,0.052,Georgia,Murray,2018-09-01, 566 | 564,0.058,Georgia,Murray,2016-03-01, 567 | 565,0.067,Georgia,Murray,2019-03-01, 568 | 566,0.067,Georgia,Murray,2016-06-01, 569 | 567,0.058,Georgia,Murray,2017-09-01, 570 | 568,0.048,Georgia,Murray,2016-02-01, 571 | 569,0.064,Georgia,Murray,2018-05-01, 572 | 570,0.058,Georgia,Murray,2016-09-01, 573 | 571,0.051,Georgia,Murray,2018-10-01, 574 | 572,0.061,Georgia,Murray,2019-05-01, 575 | 573,0.063,Georgia,Murray,2016-07-01, 576 | 574,0.069,Georgia,Murray,2016-05-01, 577 | 575,0.057,Georgia,Murray,2019-07-01, 578 | 576,0.054,Georgia,Murray,2016-08-01, 579 | 577,0.068,Georgia,Murray,2019-04-01, 580 | 578,0.066,Georgia,Murray,2017-05-01, 581 | 579,0.047,Georgia,Sumter,2018-08-01, 582 | 580,0.048,Georgia,Sumter,2017-10-01, 583 | 581,0.066,Georgia,Sumter,2016-05-01, 584 | 582,0.057,Georgia,Sumter,2018-03-01, 585 | 583,0.062,Georgia,Sumter,2018-07-01, 586 | 584,0.06,Georgia,Sumter,2018-04-01, 587 | 585,0.054,Georgia,Sumter,2019-07-01, 588 | 586,0.05,Georgia,Sumter,2017-07-01, 589 | 587,0.057,Georgia,Sumter,2019-08-01, 590 | 588,0.055,Georgia,Sumter,2016-07-01, 591 | 589,0.057,Georgia,Sumter,2019-09-01, 592 | 590,0.051,Georgia,Sumter,2018-09-01, 593 | 591,0.057,Georgia,Sumter,2017-03-01, 594 | 592,0.064,Georgia,Sumter,2018-05-01, 595 | 593,0.065,Georgia,Sumter,2019-03-01, 596 | 594,0.059,Georgia,Sumter,2017-04-01, 597 | 595,0.06,Georgia,Sumter,2017-05-01, 598 | 596,0.061,Georgia,Sumter,2016-04-01, 599 | 597,0.049,Georgia,Sumter,2017-09-01, 600 | 598,0.057,Georgia,Sumter,2016-10-01, 601 | 599,0.051,Georgia,Sumter,2016-09-01, 602 | 600,0.069,Georgia,Sumter,2019-05-01, 603 | 601,0.052,Georgia,Sumter,2019-10-01, 604 | 602,0.064,Georgia,Sumter,2018-06-01, 605 | 603,0.053,Georgia,Sumter,2017-06-01, 606 | 604,0.053,Georgia,Sumter,2018-10-01, 607 | 605,0.065,Georgia,Sumter,2016-03-01, 608 | 606,0.054,Georgia,Sumter,2017-08-01, 609 | 607,0.049,Georgia,Sumter,2016-08-01, 610 | 608,0.06,Georgia,Sumter,2019-04-01, 611 | 609,0.068,Georgia,Sumter,2019-06-01, 612 | 610,0.071,Georgia,Sumter,2016-06-01, 613 | 611,0.067,Georgia,Gwinnett,2019-05-01, 614 | 612,0.063,Georgia,Gwinnett,2017-04-01, 615 | 613,0.059,Georgia,Gwinnett,2018-03-01, 616 | 614,0.067,Georgia,Gwinnett,2016-07-01, 617 | 615,0.006,Georgia,Gwinnett,2017-02-01, 618 | 616,0.066,Georgia,Gwinnett,2016-09-01, 619 | 617,0.069,Georgia,Gwinnett,2017-05-01, 620 | 618,0.061,Georgia,Gwinnett,2019-10-01, 621 | 619,0.058,Georgia,Gwinnett,2017-03-01, 622 | 620,0.068,Georgia,Gwinnett,2019-04-01, 623 | 621,0.063,Georgia,Gwinnett,2016-08-01, 624 | 622,0.062,Georgia,Gwinnett,2019-08-01, 625 | 623,0.067,Georgia,Gwinnett,2017-09-01, 626 | 624,0.066,Georgia,Gwinnett,2018-08-01, 627 | 625,0.065,Georgia,Gwinnett,2017-07-01, 628 | 626,0.065,Georgia,Gwinnett,2018-07-01, 629 | 627,0.078,Georgia,Gwinnett,2016-05-01, 630 | 628,0.064,Georgia,Gwinnett,2017-06-01, 631 | 629,0.048,Georgia,Gwinnett,2017-10-01, 632 | 630,0.082,Georgia,Gwinnett,2016-06-01, 633 | 631,0.065,Georgia,Gwinnett,2017-08-01, 634 | 632,0.055,Georgia,Gwinnett,2018-09-01, 635 | 633,0.051,Georgia,Gwinnett,2018-10-01, 636 | 634,0.054,Georgia,Gwinnett,2016-03-01, 637 | 635,0.066,Georgia,Gwinnett,2018-05-01, 638 | 636,0.058,Georgia,Gwinnett,2016-10-01, 639 | 637,0.069,Georgia,Gwinnett,2019-07-01, 640 | 638,0.064,Georgia,Gwinnett,2018-06-01, 641 | 639,0.068,Georgia,Gwinnett,2016-04-01, 642 | 640,0.061,Georgia,Gwinnett,2019-03-01, 643 | 641,0.063,Georgia,Gwinnett,2019-06-01, 644 | 642,0.074,Georgia,Gwinnett,2019-09-01, 645 | 643,0.063,Georgia,Muscogee,2019-07-01, 646 | 644,0.057,Georgia,Muscogee,2017-07-01, 647 | 645,0.063,Georgia,Muscogee,2019-03-01, 648 | 646,0.058,Georgia,Muscogee,2016-08-01, 649 | 647,0.075,Georgia,Muscogee,2016-05-01, 650 | 648,0.054,Georgia,Muscogee,2016-03-01, 651 | 649,0.051,Georgia,Muscogee,2018-09-01, 652 | 650,0.065,Georgia,Muscogee,2019-06-01, 653 | 651,0.061,Georgia,Muscogee,2018-05-01, 654 | 652,0.06,Georgia,Muscogee,2018-04-01, 655 | 653,0.058,Georgia,Muscogee,2016-09-01, 656 | 654,0.063,Georgia,Muscogee,2017-09-01, 657 | 655,0.051,Georgia,Muscogee,2018-08-01, 658 | 656,0.057,Georgia,Muscogee,2016-07-01, 659 | 657,0.058,Georgia,Muscogee,2017-08-01, 660 | 658,0.046,Georgia,Muscogee,2017-10-01, 661 | 659,0.053,Georgia,Muscogee,2019-08-01, 662 | 660,0.052,Georgia,Muscogee,2017-06-01, 663 | 661,0.059,Georgia,Muscogee,2018-07-01, 664 | 662,0.055,Georgia,Muscogee,2018-03-01, 665 | 663,0.068,Georgia,Muscogee,2016-04-01, 666 | 664,0.056,Georgia,Muscogee,2019-10-01, 667 | 665,0.056,Georgia,Muscogee,2017-03-01, 668 | 666,0.058,Georgia,Muscogee,2019-09-01, 669 | 667,0.046,Georgia,Muscogee,2018-10-01, 670 | 668,0.065,Georgia,Muscogee,2017-05-01, 671 | 669,0.064,Georgia,Muscogee,2016-06-01, 672 | 670,0.067,Georgia,Muscogee,2019-04-01, 673 | 671,0.062,Georgia,Muscogee,2018-06-01, 674 | 672,0.055,Georgia,Muscogee,2016-10-01, 675 | 673,0.058,Georgia,Muscogee,2017-04-01, 676 | 674,0.065,Georgia,Muscogee,2019-05-01, 677 | 675,0.055,Georgia,Paulding,2016-03-01, 678 | 676,0.062,Georgia,Paulding,2016-08-01, 679 | 677,0.071,Georgia,Paulding,2016-05-01, 680 | 678,0.066,Georgia,Paulding,2016-04-01, 681 | 679,0.064,Georgia,Paulding,2016-10-01, 682 | 680,0.069,Georgia,Paulding,2016-09-01, 683 | 681,0.061,Georgia,Paulding,2016-07-01, 684 | 682,0.078,Georgia,Paulding,2016-06-01, 685 | 683,0.054,Georgia,Rockdale,2017-03-01, 686 | 684,0.065,Georgia,Rockdale,2016-10-01, 687 | 685,0.077,Georgia,Rockdale,2016-07-01, 688 | 686,0.072,Georgia,Rockdale,2019-10-01, 689 | 687,0.069,Georgia,Rockdale,2016-08-01, 690 | 688,0.06,Georgia,Rockdale,2018-03-01, 691 | 689,0.058,Georgia,Rockdale,2017-10-01, 692 | 690,0.063,Georgia,Rockdale,2017-08-01, 693 | 691,0.07,Georgia,Rockdale,2018-07-01, 694 | 692,0.079,Georgia,Rockdale,2019-08-01, 695 | 693,0.078,Georgia,Rockdale,2017-05-01, 696 | 694,0.058,Georgia,Rockdale,2017-09-01, 697 | 695,0.06,Georgia,Rockdale,2018-04-01, 698 | 696,0.062,Georgia,Rockdale,2017-06-01, 699 | 697,0.071,Georgia,Rockdale,2018-06-01, 700 | 698,0.06,Georgia,Rockdale,2019-03-01, 701 | 699,0.082,Georgia,Rockdale,2016-05-01, 702 | 700,0.067,Georgia,Rockdale,2017-07-01, 703 | 701,0.057,Georgia,Rockdale,2016-03-01, 704 | 702,0.073,Georgia,Rockdale,2019-09-01, 705 | 703,0.059,Georgia,Rockdale,2019-04-01, 706 | 704,0.069,Georgia,Rockdale,2019-05-01, 707 | 705,0.074,Georgia,Rockdale,2018-05-01, 708 | 706,0.073,Georgia,Rockdale,2019-06-01, 709 | 707,0.077,Georgia,Rockdale,2016-06-01, 710 | 708,0.054,Georgia,Rockdale,2018-09-01, 711 | 709,0.061,Georgia,Rockdale,2018-08-01, 712 | 710,0.065,Georgia,Rockdale,2017-04-01, 713 | 711,0.072,Georgia,Rockdale,2016-09-01, 714 | 712,0.067,Georgia,Rockdale,2019-07-01, 715 | 713,0.064,Georgia,Rockdale,2018-10-01, 716 | 714,0.07,Georgia,Rockdale,2016-04-01, 717 | 715,0.045,Montana,Powder River,2016-02-01, 718 | 716,0.043,Montana,Powder River,2018-12-01, 719 | 717,0.045,Montana,Powder River,2018-10-01, 720 | 718,0.048,Montana,Powder River,2016-09-01, 721 | 719,0.044,Montana,Powder River,2016-10-01, 722 | 720,0.044,Montana,Powder River,2018-01-01, 723 | 721,0.045,Montana,Powder River,2019-01-01, 724 | 722,0.055,Montana,Powder River,2017-04-01, 725 | 723,0.064,Montana,Powder River,2019-08-01, 726 | 724,0.045,Montana,Powder River,2016-03-01, 727 | 725,0.039,Montana,Powder River,2017-12-01, 728 | 726,0.058,Montana,Powder River,2016-07-01, 729 | 727,0.061,Montana,Powder River,2018-07-01, 730 | 728,0.051,Montana,Powder River,2017-10-01, 731 | 729,0.04,Montana,Powder River,2019-11-01, 732 | 730,0.055,Montana,Powder River,2019-04-01, 733 | 731,0.052,Montana,Powder River,2016-04-01, 734 | 732,0.057,Montana,Powder River,2018-09-01, 735 | 733,0.059,Montana,Powder River,2018-04-01, 736 | 734,0.046,Montana,Powder River,2017-01-01, 737 | 735,0.043,Montana,Powder River,2019-10-01, 738 | 736,0.055,Montana,Powder River,2016-06-01, 739 | 737,0.064,Montana,Powder River,2019-03-01, 740 | 738,0.063,Montana,Powder River,2018-05-01, 741 | 739,0.049,Montana,Powder River,2019-09-01, 742 | 740,0.051,Montana,Powder River,2017-03-01, 743 | 741,0.049,Montana,Powder River,2017-05-01, 744 | 742,0.061,Montana,Powder River,2017-09-01, 745 | 743,0.041,Montana,Powder River,2018-11-01, 746 | 744,0.044,Montana,Powder River,2016-12-01, 747 | 745,0.062,Montana,Powder River,2017-08-01, 748 | 746,0.055,Montana,Powder River,2019-06-01, 749 | 747,0.073,Montana,Powder River,2018-06-01, 750 | 748,0.039,Montana,Powder River,2016-11-01, 751 | 749,0.047,Montana,Powder River,2017-02-01, 752 | 750,0.057,Montana,Powder River,2017-06-01, 753 | 751,0.054,Montana,Powder River,2018-03-01, 754 | 752,0.063,Montana,Powder River,2017-07-01, 755 | 753,0.062,Montana,Powder River,2016-05-01, 756 | 754,0.064,Montana,Powder River,2019-05-01, 757 | 755,0.055,Montana,Powder River,2016-08-01, 758 | 756,0.071,Montana,Powder River,2018-08-01, 759 | 757,0.039,Montana,Powder River,2017-11-01, 760 | 758,0.04,Montana,Powder River,2016-01-01, 761 | 759,0.051,Montana,Powder River,2019-02-01, 762 | 760,0.049,Montana,Powder River,2019-07-01, 763 | 761,0.042,Montana,Powder River,2019-12-01, 764 | 762,0.059,Colorado,Weld,2019-05-01, 765 | 763,0.061,Colorado,Weld,2016-08-01, 766 | 764,0.07,Colorado,Weld,2017-06-01, 767 | 765,0.039,Colorado,Weld,2019-01-01, 768 | 766,0.062,Colorado,Weld,2019-09-01, 769 | 767,0.049,Colorado,Weld,2017-10-01, 770 | 768,0.052,Colorado,Weld,2016-10-01, 771 | 769,0.079,Colorado,Weld,2016-06-01, 772 | 770,0.051,Colorado,Weld,2017-02-01, 773 | 771,0.057,Colorado,Weld,2019-04-01, 774 | 772,0.045,Colorado,Weld,2019-10-01, 775 | 773,0.067,Colorado,Weld,2016-07-01, 776 | 774,0.068,Colorado,Weld,2019-08-01, 777 | 775,0.047,Colorado,Weld,2017-01-01, 778 | 776,0.046,Colorado,Weld,2016-01-01, 779 | 777,0.066,Colorado,Weld,2017-09-01, 780 | 778,0.074,Colorado,Weld,2018-06-01, 781 | 779,0.048,Colorado,Weld,2018-11-01, 782 | 780,0.064,Colorado,Weld,2017-04-01, 783 | 781,0.07,Colorado,Weld,2018-04-01, 784 | 782,0.066,Colorado,Weld,2016-04-01, 785 | 783,0.059,Colorado,Weld,2017-03-01, 786 | 784,0.041,Colorado,Weld,2019-12-01, 787 | 785,0.061,Colorado,Weld,2018-09-01, 788 | 786,0.055,Colorado,Weld,2018-03-01, 789 | 787,0.046,Colorado,Weld,2017-12-01, 790 | 788,0.077,Colorado,Weld,2018-05-01, 791 | 789,0.053,Colorado,Weld,2016-11-01, 792 | 790,0.062,Colorado,Weld,2016-05-01, 793 | 791,0.048,Colorado,Weld,2018-01-01, 794 | 792,0.053,Colorado,Weld,2019-03-01, 795 | 793,0.069,Colorado,Weld,2017-05-01, 796 | 794,0.055,Colorado,Weld,2016-09-01, 797 | 795,0.051,Colorado,Weld,2016-02-01, 798 | 796,0.072,Colorado,Weld,2017-08-01, 799 | 797,0.043,Colorado,Weld,2019-02-01, 800 | 798,0.076,Colorado,Weld,2017-07-01, 801 | 799,0.036,Colorado,Weld,2019-11-01, 802 | 800,0.072,Colorado,Weld,2018-07-01, 803 | 801,0.046,Colorado,Weld,2016-12-01, 804 | 802,0.065,Colorado,Weld,2019-06-01, 805 | 803,0.053,Colorado,Weld,2016-03-01, 806 | 804,0.048,Colorado,Weld,2018-10-01, 807 | 805,0.044,Colorado,Weld,2018-12-01, 808 | 806,0.05,Colorado,Weld,2018-02-01, 809 | 807,0.079,Colorado,Weld,2018-08-01, 810 | 808,0.044,Colorado,Weld,2017-11-01, 811 | 809,0.069,Colorado,Weld,2019-07-01, 812 | 810,0.065,Illinois,Will,2019-08-01, 813 | 811,0.036,Illinois,Will,2018-12-01, 814 | 812,0.046,Illinois,Will,2016-02-01, 815 | 813,0.046,Illinois,Will,2016-03-01, 816 | 814,0.072,Illinois,Will,2016-05-01, 817 | 815,0.037,Illinois,Will,2017-12-01, 818 | 816,0.044,Illinois,Will,2017-01-01, 819 | 817,0.049,Illinois,Will,2017-03-01, 820 | 818,0.061,Illinois,Will,2017-07-01, 821 | 819,0.05,Illinois,Will,2018-02-01, 822 | 820,0.049,Illinois,Will,2016-11-01, 823 | 821,0.078,Illinois,Will,2018-06-01, 824 | 822,0.054,Illinois,Will,2016-08-01, 825 | 823,0.06,Illinois,Will,2019-07-01, 826 | 824,0.06,Illinois,Will,2018-09-01, 827 | 825,0.063,Illinois,Will,2019-06-01, 828 | 826,0.03,Illinois,Will,2018-11-01, 829 | 827,0.055,Illinois,Will,2017-04-01, 830 | 828,0.037,Illinois,Will,2017-11-01, 831 | 829,0.076,Illinois,Will,2018-05-01, 832 | 830,0.052,Illinois,Will,2017-08-01, 833 | 831,0.058,Illinois,Will,2017-10-01, 834 | 832,0.056,Illinois,Will,2019-04-01, 835 | 833,0.045,Illinois,Macon,2018-02-01, 836 | 834,0.036,Illinois,Macon,2017-12-01, 837 | 835,0.031,Illinois,Macon,2018-11-01, 838 | 836,0.049,Illinois,Macon,2016-10-01, 839 | 837,0.068,Illinois,Macon,2016-04-01, 840 | 838,0.052,Illinois,Macon,2016-03-01, 841 | 839,0.057,Illinois,Macon,2017-08-01, 842 | 840,0.038,Illinois,Macon,2018-10-01, 843 | 841,0.053,Illinois,Macon,2018-09-01, 844 | 842,0.062,Illinois,Macon,2019-07-01, 845 | 843,0.06,Illinois,Macon,2017-07-01, 846 | 844,0.055,Illinois,Macon,2019-04-01, 847 | 845,0.047,Illinois,Macon,2016-11-01, 848 | 846,0.064,Illinois,Macon,2019-08-01, 849 | 847,0.032,Illinois,Macon,2016-12-01, 850 | 848,0.06,Illinois,Macon,2019-05-01, 851 | 849,0.065,Illinois,Macon,2017-09-01, 852 | 850,0.06,Illinois,Macon,2016-08-01, 853 | 851,0.065,Illinois,Macon,2016-05-01, 854 | 852,0.051,Illinois,Macon,2019-03-01, 855 | 853,0.051,Illinois,Randolph,2019-10-01, 856 | 854,0.054,Illinois,Randolph,2017-03-01, 857 | 855,0.061,Illinois,Randolph,2019-05-01, 858 | 856,0.059,Illinois,Randolph,2016-10-01, 859 | 857,0.055,Illinois,Randolph,2019-08-01, 860 | 858,0.057,Illinois,Randolph,2017-09-01, 861 | 859,0.064,Illinois,Randolph,2016-05-01, 862 | 860,0.06,Illinois,Randolph,2019-04-01, 863 | 861,0.06,Illinois,Randolph,2019-07-01, 864 | 862,0.055,Illinois,Randolph,2018-09-01, 865 | 863,0.064,Illinois,Randolph,2017-07-01, 866 | 864,0.07,Illinois,Randolph,2017-06-01, 867 | 865,0.057,Illinois,Sangamon,2016-08-01, 868 | 866,0.053,Illinois,Sangamon,2017-10-01, 869 | 867,0.062,Illinois,Sangamon,2019-07-01, 870 | 868,0.04,Illinois,Sangamon,2019-10-01, 871 | 869,0.056,Illinois,Sangamon,2016-07-01, 872 | 870,0.066,Illinois,Sangamon,2017-05-01, 873 | 871,0.043,Illinois,Sangamon,2018-10-01, 874 | 872,0.077,Illinois,Sangamon,2018-05-01, 875 | 873,0.056,Illinois,Sangamon,2019-09-01, 876 | 874,0.063,Illinois,Sangamon,2019-04-01, 877 | 875,0.053,Illinois,Sangamon,2019-03-01, 878 | 876,0.069,Illinois,Sangamon,2016-09-01, 879 | 877,0.041,Illinois,Sangamon,2016-01-01, 880 | 878,0.051,Illinois,Sangamon,2017-03-01, 881 | 879,0.058,Illinois,Sangamon,2018-09-01, 882 | 880,0.056,Illinois,Sangamon,2017-08-01, 883 | 881,0.033,Illinois,Sangamon,2018-12-01, 884 | 882,0.034,Illinois,Sangamon,2016-12-01, 885 | 883,0.06,Illinois,Sangamon,2017-04-01, 886 | 884,0.05,Illinois,Sangamon,2016-02-01, 887 | 885,0.051,Illinois,Sangamon,2018-03-01, 888 | 886,0.07,Illinois,Rock Island,2018-05-01, 889 | 887,0.05,Illinois,Rock Island,2017-02-01, 890 | 888,0.055,Illinois,Rock Island,2019-03-01, 891 | 889,0.063,Illinois,Rock Island,2016-05-01, 892 | 890,0.038,Illinois,Rock Island,2017-11-01, 893 | 891,0.053,Illinois,Rock Island,2019-09-01, 894 | 892,0.061,Illinois,Rock Island,2019-07-01, 895 | 893,0.055,Illinois,Rock Island,2016-09-01, 896 | 894,0.038,Illinois,Rock Island,2017-01-01, 897 | 895,0.048,Illinois,Rock Island,2019-10-01, 898 | 896,0.072,Illinois,Rock Island,2019-06-01, 899 | 897,0.062,Illinois,Rock Island,2017-04-01, 900 | 898,0.049,Illinois,Rock Island,2018-03-01, 901 | 899,0.047,Illinois,Rock Island,2017-03-01, 902 | 900,0.06,Illinois,Rock Island,2018-08-01, 903 | 901,0.075,Illinois,Rock Island,2019-08-01, 904 | 902,0.048,Illinois,Rock Island,2016-07-01, 905 | 903,0.04,Illinois,Rock Island,2016-11-01, 906 | 904,0.046,Illinois,Rock Island,2018-02-01, 907 | 905,0.048,California,San Francisco,2019-04-01, 908 | 906,0.031,California,San Francisco,2018-07-01, 909 | 907,0.04,California,San Francisco,2016-11-01, 910 | 908,0.043,California,San Francisco,2016-03-01, 911 | 909,0.048,California,San Francisco,2018-04-01, 912 | 910,0.049,California,San Francisco,2018-11-01, 913 | 911,0.041,California,San Francisco,2016-02-01, 914 | 912,0.054,California,San Francisco,2019-10-01, 915 | 913,0.033,California,San Francisco,2018-01-01, 916 | 914,0.04,California,San Francisco,2018-03-01, 917 | 915,0.047,California,San Francisco,2017-02-01, 918 | 916,0.047,California,San Francisco,2016-04-01, 919 | 917,0.057,California,San Francisco,2016-09-01, 920 | 918,0.042,California,San Francisco,2019-01-01, 921 | 919,0.046,California,San Francisco,2017-10-01, 922 | 920,0.046,California,San Francisco,2016-10-01, 923 | 921,0.026,California,San Francisco,2016-07-01, 924 | 922,0.039,California,San Francisco,2018-02-01, 925 | 923,0.048,California,San Francisco,2019-09-01, 926 | 924,0.043,California,San Francisco,2019-02-01, 927 | 925,0.05,California,San Francisco,2019-05-01, 928 | 926,0.038,California,San Francisco,2018-09-01, 929 | 927,0.038,California,San Francisco,2018-06-01, 930 | 928,0.039,California,San Francisco,2016-01-01, 931 | 929,0.033,California,San Francisco,2019-08-01, 932 | 930,0.054,California,San Francisco,2017-04-01, 933 | 931,0.049,California,San Francisco,2018-08-01, 934 | 932,0.047,California,San Francisco,2019-11-01, 935 | 933,0.036,California,San Francisco,2017-12-01, 936 | 934,0.04,California,San Francisco,2017-11-01, 937 | 935,0.037,California,San Francisco,2016-12-01, 938 | 936,0.041,California,San Francisco,2018-10-01, 939 | 937,0.029,California,San Francisco,2019-07-01, 940 | 938,0.041,California,San Francisco,2019-12-01, 941 | 939,0.036,California,San Francisco,2016-08-01, 942 | 940,0.041,California,San Francisco,2018-05-01, 943 | 941,0.039,California,San Francisco,2018-12-01, 944 | 942,0.028,California,San Francisco,2017-07-01, 945 | 943,0.073,California,San Francisco,2019-06-01, 946 | 944,0.033,California,San Francisco,2017-08-01, 947 | 945,0.053,California,San Francisco,2019-03-01, 948 | 946,0.044,California,San Francisco,2017-01-01, 949 | 947,0.047,California,San Francisco,2017-03-01, 950 | 948,0.036,California,San Francisco,2016-06-01, 951 | 949,0.035,California,San Francisco,2017-06-01, 952 | 950,0.052,California,San Francisco,2017-09-01, 953 | 951,0.046,California,San Francisco,2016-05-01, 954 | 952,0.038,South Dakota,Union,2019-12-01, 955 | 953,0.043,South Dakota,Union,2016-01-01, 956 | 954,0.048,South Dakota,Union,2016-03-01, 957 | 955,0.072,South Dakota,Union,2018-06-01, 958 | 956,0.045,South Dakota,Union,2019-10-01, 959 | 957,0.039,South Dakota,Union,2018-12-01, 960 | 958,0.063,South Dakota,Union,2017-05-01, 961 | 959,0.05,South Dakota,Union,2017-03-01, 962 | 960,0.051,South Dakota,Union,2018-03-01, 963 | 961,0.04,South Dakota,Union,2018-10-01, 964 | 962,0.049,South Dakota,Union,2017-08-01, 965 | 963,0.061,South Dakota,Union,2016-05-01, 966 | 964,0.041,South Dakota,Union,2019-01-01, 967 | 965,0.038,South Dakota,Union,2018-11-01, 968 | 966,0.04,South Dakota,Union,2016-12-01, 969 | 967,0.047,South Dakota,Union,2016-07-01, 970 | 968,0.07,South Dakota,Union,2017-06-01, 971 | 969,0.074,South Dakota,Union,2018-05-01, 972 | 970,0.037,South Dakota,Union,2017-12-01, 973 | 971,0.035,South Dakota,Union,2017-11-01, 974 | 972,0.057,South Dakota,Union,2019-04-01, 975 | 973,0.057,South Dakota,Union,2017-04-01, 976 | 974,0.046,South Dakota,Union,2016-10-01, 977 | 975,0.035,South Dakota,Union,2019-11-01, 978 | 976,0.051,South Dakota,Union,2016-08-01, 979 | 977,0.069,South Dakota,Union,2019-06-01, 980 | 978,0.043,South Dakota,Union,2016-02-01, 981 | 979,0.053,South Dakota,Union,2019-07-01, 982 | 980,0.046,South Dakota,Union,2018-09-01, 983 | 981,0.048,South Dakota,Union,2019-08-01, 984 | 982,0.064,South Dakota,Union,2016-06-01, 985 | 983,0.045,South Dakota,Union,2019-09-01, 986 | 984,0.046,South Dakota,Union,2017-02-01, 987 | 985,0.055,South Dakota,Union,2016-04-01, 988 | 986,0.061,South Dakota,Union,2017-07-01, 989 | 987,0.039,South Dakota,Union,2016-11-01, 990 | 988,0.056,South Dakota,Union,2016-09-01, 991 | 989,0.038,South Dakota,Union,2018-01-01, 992 | 990,0.055,South Dakota,Union,2017-10-01, 993 | 991,0.051,South Dakota,Union,2018-02-01, 994 | 992,0.055,South Dakota,Union,2018-07-01, 995 | 993,0.058,South Dakota,Union,2018-08-01, 996 | 994,0.062,South Dakota,Union,2019-02-01, 997 | 995,0.05,South Dakota,Union,2019-03-01, 998 | 996,0.045,South Dakota,Union,2017-01-01, 999 | 997,0.066,South Dakota,Union,2018-04-01, 1000 | 998,0.061,South Dakota,Union,2017-09-01, 1001 | 999,0.062,South Dakota,Union,2019-05-01, 1002 | -------------------------------------------------------------------------------- /data/zendesk_ticket_data.csv: -------------------------------------------------------------------------------- 1 | id,_fivetran_synced,allow_channelback,assignee_id,brand_id,created_at,description,due_at,external_id,forum_topic_id,group_id,has_incidents,is_public,organization_id,priority,problem_id,recipient,requester_id,status,subject,submitter_id,system_client,ticket_form_id,type,updated_at,url,via_channel,via_source_from_id,via_source_from_title,via_source_rel,via_source_to_address,via_source_to_name,merged_ticket_ids,via_source_from_address,followup_ids,via_followup_source_id 2 | 1595,2020-03-20 2:32:49,FALSE,,360003529474,2020-02-19 1:54:52,I think this is the 5th one I've purchased. I'm working on getting one in every room of my house. I ...,,,,360006965034,FALSE,TRUE,370295712714,,,email@email.com,396331237134,deleted,subject1,396331237134,,360002048693,,2020-02-19 1:55:11,https://zendesk.com/api/v2/tickets/1595.json,web,,,,example@email.com,,[],,, 3 | 16988,2021-01-13 20:09:16,FALSE,418284131934,360003529474,2020-12-22 0:19:23,"Love it! I’ve listened to songs I haven’t heard since childhood! I get the news, weather, informatio...",,,,360013366274,FALSE,TRUE,370469077513,,,email@email.com,1500656884401,solved,subject1,1500656884401,,360002048693,,2021-01-13 18:42:39,https://zendesk.com/api/v2/tickets/16988.json,email,,,,example@email.com,Support,[],,[], 4 | 14173,2020-11-11 20:08:45,FALSE,396371699653,360003529474,2020-10-28 12:03:02,"I sent it to my 85 year old Dad, and he talks to it constantly.",,,,360006965034,FALSE,TRUE,370321120273,,,email@email.com,424883466453,closed,subject1,424883466453,,360002048693,,2020-11-11 17:01:32,https://zendesk.com/api/v2/tickets/14173.json,email,,,,example@email.com,Support,[],,, 5 | 11071,2020-10-02 14:08:33,FALSE,,360003529474,2020-08-28 18:06:36,"I love it, wife hates it.",,,,,FALSE,TRUE,,,,email@email.com,419755385214,deleted,subject1,419755385214,,360002048693,,2020-09-02 11:01:27,https://zendesk.com/api/v2/tickets/11071.json,email,,,,X,Support,[],,, 6 | 1966,2020-03-25 20:32:24,FALSE,396315360434,360003529474,2020-02-27 6:05:08,She doesn’t always listen,,,,360006965034,FALSE,TRUE,370295721514,,,email@email.com,402813302773,closed,subject1,402813302773,,360002048693,,2020-03-25 16:03:26,https://zendesk.com/api/v2/tickets/1966.json,email,,,,example@email.com,Support,[1967],,, 7 | 11013,2020-10-02 20:08:20,FALSE,402851697393,360003529474,2020-08-27 23:09:52,I was a little nervous when I received my new Echo as I'm not really Tech savvy. I found it a bit in...,,,,360008376313,FALSE,TRUE,370297881854,,,email@email.com,419688934974,deleted,subject1,419688934974,,360002048693,,2020-09-02 15:53:16,https://zendesk.com/api/v2/tickets/11013.json,email,,,,X,Support,[],,, 8 | 1404,2020-03-05 4:53:46,FALSE,396371699653,360003529474,2020-02-13 21:43:58,Some major design flaws,,,,360006965034,FALSE,TRUE,370295709874,,,email@email.com,403125197514,closed,subject1,403125197514,,360002048693,,2020-02-28 1:01:57,https://zendesk.com/api/v2/tickets/1404.json,email,,,,example@email.com,Support,,,, 9 | 4721,2020-05-14 20:12:36,FALSE,396371706773,360003529474,2020-04-20 14:31:46,Huge disappointment,,,,360006965034,FALSE,TRUE,370295719414,,,email@email.com,402862357193,closed,subject1,402862357193,,360002048693,,2020-05-14 20:04:34,https://zendesk.com/api/v2/tickets/4721.json,email,,,,example@email.com,Support,[],,, 10 | 6171,2020-06-01 2:11:40,FALSE,396334400494,360003529474,2020-05-17 17:50:31,"nice hotel expensive parking got good deal stay hotel anniversary, arrived late evening ",,,,360006965034,FALSE,TRUE,370295713034,,,email@email.com,410930434074,closed,subject1,410930434074,,360002048693,,2020-05-31 23:03:46,https://zendesk.com/api/v2/tickets/6171.json,email,,,,example@email.com,Support,[],,, 11 | 6605,2020-06-10 2:10:24,FALSE,396315360434,360003529474,2020-05-26 22:29:50,Full display not working in all application.,,,,360006965034,FALSE,TRUE,370295719754,,,email@email.com,410416672973,closed,subject1,410416672973,,360002048693,,2020-06-09 23:03:49,https://zendesk.com/api/v2/tickets/6605.json,email,,,,example@email.com,Support,[],,, -------------------------------------------------------------------------------- /dbt_project.yml: -------------------------------------------------------------------------------- 1 | # Name your project! Project names should contain only lowercase characters 2 | # and underscores. A good package name should reflect your organization's 3 | # name or the intended use of these models 4 | name: "fal_dbt_examples" 5 | version: "1.0.0" 6 | config-version: 2 7 | 8 | # This setting configures which "profile" dbt uses for this project. 9 | profile: "fal_dbt_examples" 10 | 11 | # These configurations specify where dbt should look for different types of files. 12 | # The `source-paths` config, for example, states that models in this project can be 13 | # found in the "models/" directory. You probably won't need to change these! 14 | source-paths: ["models"] 15 | analysis-paths: ["analysis"] 16 | test-paths: ["tests"] 17 | data-paths: ["data"] 18 | macro-paths: ["macros"] 19 | snapshot-paths: ["snapshots"] 20 | 21 | target-path: "target" # directory which will store compiled SQL files 22 | clean-targets: # directories to be removed by `dbt clean` 23 | - "target" 24 | - "dbt_modules" 25 | 26 | # Configuring models 27 | # Full documentation: https://docs.getdbt.com/docs/configuring-models 28 | 29 | # In this example config, we tell dbt to build all models in the example/ directory 30 | # as tables. These settings can be overridden in the individual model files 31 | # using the `{{ config(...) }}` macro. 32 | models: 33 | -------------------------------------------------------------------------------- /fal_scripts/anomaly_detection.py: -------------------------------------------------------------------------------- 1 | """Finding anomalies on a dataset using DBSCAN 2 | 3 | Dependencies: 4 | - sklearn 5 | - slack_sdk 6 | - 7 | 8 | Follow instructions in slack.py for setting up a minimal Slack bot. 9 | 10 | This example is built for a model that has two columns: y and ds, where 11 | y is a metric measure and ds is a timestamp. 12 | 13 | The metric that we look at is Agent Wait Time in minutes. 14 | """ 15 | import os 16 | from numpy.core.fromnumeric import size 17 | from sklearn.cluster import DBSCAN, KMeans 18 | from sklearn.metrics import silhouette_score 19 | from slack_sdk import WebClient 20 | from slack_sdk.errors import SlackApiError 21 | import numpy as np 22 | import pandas as pd 23 | import matplotlib.pyplot as plt 24 | import datetime 25 | from math import floor 26 | import ssl 27 | 28 | CHANNEL_ID = os.getenv("SLACK_BOT_CHANNEL") 29 | SLACK_TOKEN = os.getenv("SLACK_BOT_TOKEN") 30 | TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo 31 | PATH_PREFIX = os.getcwd() 32 | 33 | def anomaly_detection(X: np.array, eps: float, min_samples: int, window_size: int): 34 | """Find anomalies on given time-series numerical data. 35 | 36 | Parameters 37 | ---------- 38 | X: numpy.array 39 | A numpy array with shape (-1,1) containing time-series 40 | numerical data. I. e. a column of a multi-feature dataset. 41 | eps: float 42 | The epsilon value for DBSCAN. It is one of the two 43 | hyperparameters that needs fine tuning for good results. 44 | min_samples: int 45 | The minimum samples value for DBSCAN. It is one of the two 46 | hyperparameters that needs fine tuning for good results. 47 | window_size: int 48 | The window size for applying sliding windows on the data. 49 | Applying sliding windows to the data before applying DBSCAN 50 | improves the performance of the system. 51 | 52 | Returns 53 | ------- 54 | anomalies: numpy.array 55 | A numpy array with the indices of the anomalies found on 56 | the data, the indices are with respect to the input data, X. 57 | """ 58 | X_windowed = np.lib.stride_tricks.sliding_window_view(x=X, window_shape=window_size, axis=0) 59 | (size_0, _, _) = X_windowed.shape 60 | anomalies = [] 61 | 62 | for window in range(size_0): 63 | clustering = DBSCAN(eps=eps, min_samples=min_samples).fit(X_windowed[window][0][:].reshape(-1,1)) 64 | labels = clustering.labels_ 65 | location = np.where(labels == -1) 66 | location = location[0] 67 | size = location.size 68 | if size != 0: 69 | if size == 1: 70 | anomalies.append(location[0] + window) 71 | else: 72 | for i in range(size): 73 | anomalies.append(location[i] + window) 74 | else: 75 | continue 76 | 77 | anomalies = np.unique(np.array(anomalies)) 78 | 79 | return anomalies 80 | 81 | def find_ideal_min_samples(X: np.array, range_min_samples: list): 82 | """Finds the ideal min_samples value from a given range of min_samples. 83 | Parameters 84 | ---------- 85 | X: numpy.array 86 | A numpy array with shape (-1,1) containing time-series 87 | numerical data. I. e. a column of a multi-feature dataset. 88 | range_min_samples: list of ints 89 | A list with possible min_samples candidates. 90 | Returns 91 | ------- 92 | ideal_min_sample: int 93 | The ideal min_sample value for DBSCAN for X. 94 | """ 95 | X_windowed = np.lib.stride_tricks.sliding_window_view(x=X, window_shape=window_size, axis=0) 96 | (size_0, _, _) = X_windowed.shape 97 | 98 | min_sample_scores = np.zeros(shape=(1, len(range_min_samples))) 99 | 100 | for window in range(size_0): 101 | for i in range(len(range_min_samples)): 102 | clustering = KMeans(n_clusters=range_min_samples[i]) 103 | cluster_labels = clustering.fit_predict(X_windowed[window][0][:].reshape(-1,1)) 104 | silhouette_avg = silhouette_score(X_windowed[window][0][:].reshape(-1,1), cluster_labels) 105 | min_sample_scores[0][i] = min_sample_scores[0][i]+silhouette_avg 106 | 107 | min_sample_scores = min_sample_scores / size_0 108 | ideal_min_sample = range_min_samples[np.where(min_sample_scores.max)[0][0]] 109 | 110 | return ideal_min_sample 111 | 112 | def find_eps_range(X: np.array, range_const: int): 113 | """Creates two matplotlib figures with one being a plot of 114 | the distance between samples and the other one being a bounded 115 | version of the first plot. It is used to see if the bounded plot 116 | resembles an elbow curve. The range constant is arbitrarily chosen 117 | and fine tuned by hand to find a range with an elbow curve. 118 | Parameters 119 | ---------- 120 | X: numpy.array 121 | A numpy array with shape (-1,1) containing time-series 122 | numerical data. I. e. a column of a multi-feature dataset. 123 | range_const: int 124 | A constant that the epsilon range is constructed. Usually 125 | 2.5% of the maximum value of the dataset makes a good starting 126 | point. 127 | 128 | Returns 129 | ------- 130 | None 131 | """ 132 | dists = np.zeros_like(X) 133 | for i in range(X.size-1): 134 | dist = np.linalg.norm(X[i]-X[i+1]) 135 | dists[i] = dist 136 | dists = np.sort(dists, axis=0) 137 | 138 | plt.plot([i for i in range(dists.size)], dists, 'b.', markersize=4) 139 | plt.xlabel('Time') 140 | plt.ylabel('Value') 141 | plt.savefig(f'{PATH_PREFIX}/fal_scripts/anomaly_detection_other/distance_between_samples.jpg') 142 | plt.clf() 143 | 144 | bounded_dists_i = np.where(dists<=range_const*5)[0] 145 | plt.plot(bounded_dists_i, [dists[i] for i in bounded_dists_i], 'b.', markersize=4) 146 | plt.xlabel('Time') 147 | plt.ylabel('Value') 148 | plt.savefig(f'{PATH_PREFIX}/fal_scripts/anomaly_detection_other/distance_between_samples_bounded.jpg') 149 | plt.clf() 150 | 151 | def find_ideal_eps(X: np.array, min_samples: int, window_size: int, range_eps: list): 152 | """Finds the ideal min_samples value from a given range of 153 | min_samples. 154 | Parameters 155 | ---------- 156 | X: numpy.array 157 | A numpy array with shape (-1,1) containing time-series 158 | numerical data. I. e. a column of a multi-feature dataset. 159 | min_samples: int 160 | The minimum samples value for DBSCAN. It is one of the two 161 | hyperparameters that needs fine tuning for good results. 162 | window_size: int 163 | The window size for applying sliding windows on the data. 164 | Applying sliding windows to the data before applying DBSCAN 165 | improves the performance of the system. 166 | range_eps: list of ints 167 | A list with possible min_samples candidates. 168 | 169 | Returns 170 | ------- 171 | ideal_eps: float 172 | The ideal epsilon value for DBSCAN for X. 173 | 174 | """ 175 | X_windowed = np.lib.stride_tricks.sliding_window_view(x=X, window_shape=window_size, axis=0) 176 | (size_0, _, _) = X_windowed.shape 177 | 178 | eps_scores = np.zeros(shape=(1, len(range_eps))) 179 | 180 | for window in range(size_0): 181 | for i in range(len(range_eps)): 182 | clustering = DBSCAN(eps=range_eps[i], min_samples=min_samples).fit(X_windowed[window][0][:].reshape(-1,1)) 183 | labels = clustering.labels_ 184 | if np.unique(labels).size > 1: 185 | silhouette_avg = silhouette_score(X_windowed[window][0][:].reshape(-1,1), labels) 186 | eps_scores[0][i] = eps_scores[0][i]+silhouette_avg 187 | 188 | eps_scores = eps_scores / size_0 189 | 190 | ideal_eps = range_eps[np.where(eps_scores.max)[0][0]] 191 | 192 | return ideal_eps 193 | 194 | def plot_anomalies(column_y: np.array, column_date: np.array, anomalies: np.array): 195 | """Plots the data and notes the anomalies on a matplotlib figure 196 | and returns the location of a JPG of the figure. 197 | 198 | Parameters 199 | ---------- 200 | column_y: np.array 201 | A numpy array containing one column of values of a time-series 202 | dataset. 203 | column_date: np.array 204 | A numpy array containing the time objects of a time-series 205 | dataset. 206 | anomalies: 207 | A numpy array containing the indices of the anomalous data 208 | points. 209 | 210 | Returns 211 | ------- 212 | fname: string 213 | The path of the matplotlib figure with the data plotted and 214 | anomailes 215 | noted. 216 | """ 217 | fig = plt.figure(figsize=(15,5)) 218 | axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) 219 | axes.plot([column_date[i] for i in range(column_y.size)], column_y, 'b.', markersize=4) 220 | axes.plot([column_date[i] for i in anomalies], [column_y[i] for i in anomalies], 'r^', markersize=4) 221 | axes.set_xlabel('Time') 222 | axes.set_ylabel('Value') 223 | axes.legend(['Actual', 'Anomaly Found']) 224 | now = str(datetime.datetime.now()) 225 | now = now[:10]+'-'+now[11:13]+now[14:16] 226 | fpath = f'{PATH_PREFIX}/fal_scripts/anomaly_detection/{now}-{TIMEZONE}.jpg' 227 | fig.savefig(fname=fpath) 228 | plt.clf() 229 | 230 | return fpath 231 | 232 | # is the same slack file sending function from forecast_slack.py 233 | def send_slack_file(file_path: str, message_text: str, channel_id: str, slack_token: str): 234 | """Sends a file and message to Slack. 235 | Parameters 236 | ---------- 237 | file_path: string 238 | The file path of the file that needs to be sent. 239 | message_text: string 240 | The messange that needs to be sent along with the text. 241 | channel_id: string 242 | Channel ID for the Slack channel that the message needs 243 | to be sent to. 244 | slack_token: string 245 | Slack token for the Slack bot that is going to be used. 246 | 247 | Returns 248 | ------- 249 | None 250 | """ 251 | client = WebClient(token=slack_token) 252 | 253 | try: 254 | client.files_upload( 255 | channels=channel_id, 256 | file=file_path, 257 | title="fal.ai anomaly detection", 258 | initial_comment=message_text, 259 | ) 260 | except SlackApiError as e: 261 | assert e.response["error"] 262 | 263 | model_df = ref(context.current_model.name).sort_values(by='ds') 264 | 265 | column_y = model_df['y'].to_numpy(dtype=np.float).reshape(-1,1) 266 | column_date = model_df['ds'].to_numpy(dtype=datetime.datetime).reshape(-1,1) 267 | 268 | window_size = 100 269 | 270 | range_min_samples = [2,3,4,5] 271 | min_samples = find_ideal_min_samples(column_y, range_min_samples) 272 | 273 | range_const = int(floor(np.amax(column_y)*0.02)) 274 | find_eps_range(column_y, range_const) 275 | range_eps = range(range_const, (range_const*5)+1, range_const) 276 | 277 | eps = find_ideal_eps(column_y, min_samples, window_size, range_eps) 278 | 279 | anomalies = anomaly_detection(column_y, eps, min_samples, window_size) 280 | fpath = plot_anomalies(column_y, column_date, anomalies) 281 | now = str(datetime.datetime.now()) 282 | date = now[:10] 283 | hour = now[11:13]+now[14:16] 284 | 285 | print(f'anomalies: {anomalies.size}\ndata: {column_y.size}\npercentage: {(anomalies.size/column_y.size)*100}%') 286 | 287 | # This is to get around a bug, usually it is not needed. 288 | ssl._create_default_https_context = ssl._create_unverified_context 289 | 290 | message = f'fal.ai anomaly detection.\nFound {anomalies.size} anomalies.\nModel: {context.current_model.name}\nDate: {date}\nTime: {hour}-{TIMEZONE}\neps: {eps}, min_samples: {min_samples}, window_size: {window_size}' 291 | send_slack_file(fpath, message, CHANNEL_ID, SLACK_TOKEN) 292 | -------------------------------------------------------------------------------- /fal_scripts/anomaly_detection/2021-11-20-2054-CET.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/fal_scripts/anomaly_detection/2021-11-20-2054-CET.jpg -------------------------------------------------------------------------------- /fal_scripts/anomaly_detection/2021-11-20-2204-CET.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/fal_scripts/anomaly_detection/2021-11-20-2204-CET.jpg -------------------------------------------------------------------------------- /fal_scripts/anomaly_detection/2021-11-20-2207-CET.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/fal_scripts/anomaly_detection/2021-11-20-2207-CET.jpg -------------------------------------------------------------------------------- /fal_scripts/anomaly_detection/2021-11-20-2215-CET.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/fal_scripts/anomaly_detection/2021-11-20-2215-CET.jpg -------------------------------------------------------------------------------- /fal_scripts/anomaly_detection/2021-11-20-2322-CET.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/fal_scripts/anomaly_detection/2021-11-20-2322-CET.jpg -------------------------------------------------------------------------------- /fal_scripts/anomaly_detection_other/distance_between_samples.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/fal_scripts/anomaly_detection_other/distance_between_samples.jpg -------------------------------------------------------------------------------- /fal_scripts/anomaly_detection_other/distance_between_samples_bounded.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/fal_scripts/anomaly_detection_other/distance_between_samples_bounded.jpg -------------------------------------------------------------------------------- /fal_scripts/forecast_slack.py: -------------------------------------------------------------------------------- 1 | """Send an forecasted data plot to Slack. 2 | 3 | Dependencies: 4 | - slack_sdk 5 | - fbprophet 6 | 7 | Follow instructions in slack.py for setting up a minimal Slack bot. 8 | 9 | This example is built for a model that has two columns: y and ds, where 10 | y is a metric measure and ds is a timestamp. 11 | 12 | The metric that we look at is Agent Wait Time in minutes. 13 | """ 14 | 15 | import os 16 | import pandas as pd 17 | import datetime 18 | import time 19 | from slack_sdk import WebClient 20 | from slack_sdk.errors import SlackApiError 21 | from fbprophet import Prophet 22 | from fbprophet.plot import plot_plotly 23 | 24 | 25 | FORECAST_PREFIX = "fal_forecast_" 26 | CHANNEL_ID = os.getenv("SLACK_BOT_CHANNEL") 27 | SLACK_TOKEN = os.getenv("SLACK_BOT_TOKEN") 28 | 29 | 30 | def make_forecast(dataframe: pd.DataFrame, filename: str): 31 | """Make forecast on metric data.""" 32 | m = Prophet() 33 | m.fit(dataframe) 34 | 35 | n_future_days = 30 36 | ds = dataframe["ds"].max() 37 | future_dates = [] 38 | for _ in range(n_future_days): 39 | ds = ds + datetime.timedelta(days=1) 40 | future_dates.append(ds) 41 | df_future = pd.DataFrame({"ds": future_dates}) 42 | forecast = m.predict(df_future) 43 | fig = plot_plotly(m, forecast, xlabel="Date", ylabel="Agent Wait Time") 44 | fig.write_image(filename) 45 | return filename 46 | 47 | 48 | def send_slack_file( 49 | file_path: str, message_text: str, channel_id: str, slack_token: str 50 | ): 51 | """Send file to slack.""" 52 | client = WebClient(token=slack_token) 53 | 54 | try: 55 | client.files_upload( 56 | channels=channel_id, 57 | file=file_path, 58 | title="FAL forecast", 59 | initial_comment=message_text, 60 | ) 61 | except SlackApiError as e: 62 | assert e.response["error"] 63 | 64 | 65 | def forecast(message): 66 | """Make forecast on a model and send plot to Slack.""" 67 | df = ref(context.current_model.name) 68 | forecast = make_forecast( 69 | dataframe=df, filename=f"{FORECAST_PREFIX}{time.time()}.png" 70 | ) 71 | send_slack_file( 72 | file_path=forecast, 73 | message_text=message, 74 | channel_id=CHANNEL_ID, 75 | slack_token=SLACK_TOKEN, 76 | ) 77 | 78 | 79 | forecast('zendesk forecast') 80 | -------------------------------------------------------------------------------- /fal_scripts/list_owners_of_models.py: -------------------------------------------------------------------------------- 1 | models = list_models() 2 | 3 | for model in models: 4 | if model.meta: 5 | print(model.meta["owner"]) 6 | -------------------------------------------------------------------------------- /fal_scripts/load_o3_data.py: -------------------------------------------------------------------------------- 1 | import pandas 2 | 3 | cols = ['O3', 'state', 'county', 'month'] 4 | df = pandas.read_csv('data/raw_o3_values.csv', usecols=cols) 5 | write_to_source(df, "results", "raw_o3_values") 6 | -------------------------------------------------------------------------------- /fal_scripts/send_datadog_event.py: -------------------------------------------------------------------------------- 1 | """Send event with model information to Datadog.""" 2 | from datadog_api_client.v1 import ApiClient, ApiException, Configuration 3 | from datadog_api_client.v1.api import events_api 4 | from datadog_api_client.v1.models import EventCreateRequest 5 | import os 6 | import time 7 | import io 8 | 9 | current_time = time.time() 10 | 11 | configuration = Configuration() 12 | configuration.api_key['apiKeyAuth'] = os.getenv("DD_API_KEY") 13 | configuration.api_key['appKeyAuth'] = os.getenv("DD_APP_KEY") 14 | 15 | df = ref(context.current_model.name) 16 | 17 | buf = io.StringIO() 18 | df.info(buf=buf) 19 | 20 | text = buf.getvalue() 21 | tags = ["fal"] 22 | 23 | event_body = EventCreateRequest( 24 | tags=tags, 25 | aggregation_key="fal", 26 | title="fal - event", 27 | text=text, 28 | date_happened=int(current_time) 29 | ) 30 | 31 | 32 | with ApiClient(configuration) as api_client: 33 | # Create an instance of the API class 34 | events_api_instance = events_api.EventsApi(api_client) 35 | try: 36 | events_api_instance.create_event(event_body) 37 | except ApiException as e: 38 | assert e.response["error"] 39 | -------------------------------------------------------------------------------- /fal_scripts/slack.py: -------------------------------------------------------------------------------- 1 | """Send Slack messages from your dbt project. 2 | 3 | You can use fal to send Slack messages. 4 | A Slack App needs to be properly set up first: 5 | 6 | 1. Create a Slack App 7 | 8 | Follow instructions on this page in order to create an organization-specific 9 | Slack app: 10 | 11 | https://slack.com/help/articles/115005265703-Create-a-bot-for-your-workspace 12 | 13 | Add following OAuth Scopes: 14 | 15 | - `channels:join` 16 | - `chat:write` 17 | - `files:write` 18 | - `app_mentions:read` 19 | - `groups:read` 20 | 21 | 2. Install the app and get the bot token 22 | 23 | On the same "OAuth & Permissions" page, click on "Install to Workspace" button, 24 | proceed with installation and take note of the provided Bot User OAuth Token. 25 | 26 | 3. Get channel ID 27 | 28 | In Slack, right click on the channel that you want fal to publish to, click on 29 | "Open channel details" and copy the Channel ID on the bottom of the modal. 30 | 31 | 4. Add your bot to your channel 32 | 33 | In your Slack channel, type following message: 34 | 35 | /add @your_bot_name 36 | 37 | 5. Set environment variables 38 | 39 | In terminal set following two environment variable: SLACK_BOT_TOKEN and 40 | SLACK_BOT_CHANNEL. This can be done with export command: 41 | 42 | export SLACK_BOT_TOKEN=your-bot-token 43 | export SLACK_TARGET_CHANNEL=your-target-channel 44 | """ 45 | 46 | import os 47 | from slack_sdk import WebClient 48 | from slack_sdk.errors import SlackApiError 49 | 50 | CHANNEL_ID = os.getenv("SLACK_BOT_CHANNEL") 51 | SLACK_TOKEN = os.getenv("SLACK_BOT_TOKEN") 52 | 53 | client = WebClient(token=SLACK_TOKEN) 54 | message_text = f"Model: {context.current_model.name}. Status: {context.current_model.status}." 55 | 56 | try: 57 | response = client.chat_postMessage( 58 | channel=CHANNEL_ID, 59 | text=message_text 60 | ) 61 | except SlackApiError as e: 62 | # You will get a SlackApiError if "ok" is False 63 | assert e.response["error"] 64 | -------------------------------------------------------------------------------- /fal_scripts/upload_to_gcs.py: -------------------------------------------------------------------------------- 1 | import os 2 | from google.cloud import storage 3 | 4 | bucket_name = "fal_example_dbt_artifacts_bucket" 5 | manifest_destination_blob_name = "manifest.json" 6 | run_results_destination_blob_name = "run_results.json" 7 | 8 | manifest_source_file_name = os.path.join(context.config.target_path, "manifest.json") 9 | run_results_source_file_name = os.path.join(context.config.target_path, "run_results.json") 10 | 11 | storage_client = storage.Client() 12 | bucket = storage_client.bucket(bucket_name) 13 | manifest_blob = bucket.blob(manifest_destination_blob_name) 14 | run_results_blob = bucket.blob(run_results_destination_blob_name) 15 | 16 | manifest_blob.upload_from_filename(manifest_source_file_name) 17 | run_results_blob.upload_from_filename(run_results_source_file_name) 18 | -------------------------------------------------------------------------------- /fal_scripts/upload_to_s3.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | 4 | s3_client = boto3.client('s3') 5 | 6 | bucket_name = "fal-example-dbt-artifacts-bucket" 7 | manifest_source_file_name = os.path.join(context.config.target_path, "manifest.json") 8 | run_results_source_file_name = os.path.join(context.config.target_path, "run_results.json") 9 | manifest_destination_blob_name = "manifest.json" 10 | run_results_destination_blob_name = "run_results.json" 11 | 12 | 13 | s3_client.upload_file(manifest_source_file_name, bucket_name, manifest_destination_blob_name) 14 | s3_client.upload_file(run_results_source_file_name, bucket_name, run_results_destination_blob_name) 15 | -------------------------------------------------------------------------------- /fal_scripts/write_to_firestore.py: -------------------------------------------------------------------------------- 1 | """Send model data to Firestore.""" 2 | 3 | df = ref(context.current_model.name) 4 | 5 | write_to_firestore(df=df, 6 | collection="zendesk_sentiment_data", 7 | key_column="id") 8 | 9 | print("Success!") 10 | -------------------------------------------------------------------------------- /fal_scripts/zendesk_sentiment_analysis.py: -------------------------------------------------------------------------------- 1 | from transformers import pipeline 2 | import pandas as pd 3 | import numpy as np 4 | 5 | ticket_data = ref("stg_zendesk_ticket_data") 6 | ticket_descriptions = list(ticket_data.description) 7 | classifier = pipeline("sentiment-analysis") 8 | description_sentimet_analysis = classifier(ticket_descriptions) 9 | 10 | rows = [] 11 | for id, sentiment in zip(ticket_data.id, description_sentimet_analysis): 12 | rows.append((int(id), sentiment["label"], sentiment["score"])) 13 | 14 | records = np.array(rows, dtype=[("id", int), ("label", "U8"), ("score", float)]) 15 | 16 | sentiment_df = pd.DataFrame.from_records(records) 17 | 18 | print("Uploading\n", sentiment_df) 19 | write_to_source(sentiment_df, "results", "ticket_data_sentiment_analysis") 20 | -------------------------------------------------------------------------------- /macros/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/macros/.gitkeep -------------------------------------------------------------------------------- /models/boston.sql: -------------------------------------------------------------------------------- 1 | WITH o3values as 2 | (SELECT * FROM {{ ref('stg_o3values') }}) 3 | 4 | SELECT 5 | O3 as y, 6 | month as ds 7 | FROM 8 | o3values 9 | WHERE 10 | state = 'Massachusetts' 11 | AND county = 'Middlesex' 12 | -------------------------------------------------------------------------------- /models/lombardia_covid.sql: -------------------------------------------------------------------------------- 1 | {{ config(materialized='table') }} 2 | 3 | WITH source_data as ( 4 | select * from {{ ref('covid19_italy_region') }} 5 | ) 6 | 7 | SELECT 8 | NewPositiveCases as y, 9 | Date as ds 10 | FROM 11 | source_data 12 | WHERE 13 | RegionCode = 3 -------------------------------------------------------------------------------- /models/miami.sql: -------------------------------------------------------------------------------- 1 | WITH o3values as 2 | (SELECT * FROM `{{ env_var('GCLOUD_PROJECT') }}.{{ env_var('BQ_DATASET') }}.raw_o3_values`) 3 | 4 | SELECT 5 | O3 as y, 6 | month as ds 7 | FROM 8 | o3values 9 | WHERE 10 | state = 'Florida' 11 | AND county = 'Miami-Dade' 12 | -------------------------------------------------------------------------------- /models/schema.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | sources: 4 | - name: results 5 | database: "{{ env_var('GCLOUD_PROJECT') }}" 6 | schema: "{{ env_var('BQ_DATASET') }}" 7 | tables: 8 | - name: ticket_data_sentiment_analysis 9 | - name: raw_o3_values 10 | 11 | models: 12 | - name: boston 13 | description: Ozone levels 14 | config: 15 | materialized: table 16 | meta: 17 | owner: "@meder" 18 | fal: 19 | scripts: 20 | - fal_scripts/slack.py 21 | - fal_scripts/send_datadog_event.py 22 | 23 | - name: miami 24 | description: Ozone levels in Miami 25 | config: 26 | materialized: table 27 | meta: 28 | owner: "@meder" 29 | fal: 30 | scripts: 31 | before: 32 | - fal_scripts/load_o3_data.py 33 | after: 34 | - fal_scripts/slack.py 35 | 36 | - name: stg_zendesk_ticket_data 37 | description: zendesk ticket data 38 | config: 39 | materialized: table 40 | meta: 41 | owner: "@meder" 42 | fal: 43 | scripts: 44 | - fal_scripts/slack.py 45 | - fal_scripts/write_to_firestore.py 46 | - fal_scripts/zendesk_sentiment_analysis.py 47 | - name: zendesk_ticket_metrics 48 | description: Zendesk ticket metrics 49 | config: 50 | materialized: table 51 | meta: 52 | owner: "@gorkem" 53 | fal: 54 | scripts: 55 | - fal_scripts/forecast_slack.py 56 | - name: lombardia_covid 57 | description: Lombardia (IT) Covid19 Cases 58 | config: 59 | materialized: table 60 | meta: 61 | owner: "@omer" 62 | fal: 63 | scripts: 64 | - fal_scripts/anomaly_detection.py 65 | 66 | fal: 67 | scripts: 68 | - fal_scripts/list_owners_of_models.py 69 | - fal_scripts/upload_to_gcs.py 70 | - fal_scripts/upload_to_s3.py 71 | -------------------------------------------------------------------------------- /models/stg_counties.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM `bigquery-public-data.geo_us_boundaries.counties` 2 | -------------------------------------------------------------------------------- /models/stg_o3values.sql: -------------------------------------------------------------------------------- 1 | WITH o3values as 2 | (SELECT * 3 | FROM `bigquery-public-data.epa_historical_air_quality.o3_daily_summary`), 4 | counties as 5 | (SELECT * 6 | FROM {{ ref('stg_counties') }}) 7 | 8 | SELECT MAX(o3values.first_max_value) as O3, 9 | o3values.state_name as state, 10 | o3values.county_name as county, 11 | DATE_TRUNC(o3values.date_local, MONTH) as month, 12 | ANY_VALUE(counties.county_geom) as geom 13 | FROM o3values 14 | LEFT JOIN counties on CONCAT(o3values.state_code, o3values.county_code) = counties.county_fips_code 15 | WHERE o3values.date_local >= DATE('2016-01-01') 16 | GROUP BY 2, 17 | 3, 18 | 4 19 | -------------------------------------------------------------------------------- /models/stg_zendesk_ticket_data.sql: -------------------------------------------------------------------------------- 1 | {{ config(materialized='table') }} 2 | 3 | with source_data as ( 4 | 5 | select * from {{ ref('zendesk_ticket_data') }} 6 | ) 7 | 8 | select * 9 | from source_data 10 | -------------------------------------------------------------------------------- /models/zendesk_ticket_metrics.sql: -------------------------------------------------------------------------------- 1 | -- source table contains zendesk ticket data 2 | -- more info: https://developer.zendesk.com/api-reference/ticketing/tickets/ticket_metrics/ 3 | 4 | SELECT agent_wait_time_in_minutes.business as y, 5 | CAST(DATE(created_at) as DATE) as ds 6 | FROM `{{ env_var('GCLOUD_PROJECT') }}.{{ env_var('BQ_DATASET') }}.zendesk_ticket_metric_data` 7 | -------------------------------------------------------------------------------- /profiles.yml: -------------------------------------------------------------------------------- 1 | fal_dbt_examples: 2 | target: dev 3 | outputs: 4 | dev: 5 | type: bigquery 6 | method: service-account 7 | keyfile: "{{ env_var('KEYFILE_DIR') }}/keyfile.json" 8 | project: "{{ env_var('GCLOUD_PROJECT') }}" 9 | dataset: "{{ env_var('BQ_DATASET') }}" 10 | threads: 1 11 | timeout_seconds: 300 12 | location: US 13 | priority: interactive 14 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Core dependencies 2 | fal=0.2.7 3 | 4 | # Script dependencies 5 | ## Forecasting 6 | pystan==2.18.0 7 | kaleido 8 | fbprophet 9 | plotly 10 | numpy 11 | 12 | ## Anomaly detection 13 | sklearn 14 | 15 | ## Slack 16 | slack_sdk 17 | 18 | # Datadog 19 | datadog_api_client 20 | 21 | # Sentiment analysis 22 | transformers 23 | torch 24 | 25 | # Upload to S3 26 | boto3 27 | -------------------------------------------------------------------------------- /snapshots/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/snapshots/.gitkeep -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/tests/.gitkeep -------------------------------------------------------------------------------- /weighted_label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fal-ai/fal_dbt_examples/38252cb306521c8550965b9ffdc21fa9054f2d02/weighted_label.png --------------------------------------------------------------------------------