-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
1400 lines (1369 loc) · 75.6 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>tanzhijian.org</title>
<id>https://tanzhijian.org/atom.xml</id>
<updated>2024-09-29T22:32:03Z</updated>
<link href="tanzhijian.org"/>
<link href="https://tanzhijian.org/atom.xml" rel="self"/>
<generator>?</generator>
<entry>
<title>Statsbomb 的传球分析</title>
<link href="https://tanzhijian.org/posts/statsbomb_analysing_passing_rofiles"></link>
<id>1727620323.5612075</id>
<updated>2024-09-29T22:32:03Z</updated>
<published>2024-09-29T22:32:03Z</published>
<author><name>tanzhijian</name></author>
<summary>最近收到一份 Stamsbomb 的推送报告,附件包含他们瑞典,丹麦,挪威联赛的传球数据报告,不太清楚他们的版权规定,但可以写一些结论性的东西。
</summary>
<content type="html">
<h1>Statsbomb 的传球分析</h1>
<p>最近收到一份 Stamsbomb 的推送报告,附件包含他们瑞典,丹麦,挪威联赛的传球数据报告,不太清楚他们的版权规定,但可以写一些结论性的东西。</p>
<p>报告的主要目的是研究比赛通常比赛中的传球类型;哪些传球为比赛增加了最大的价值,以及球员是否有效的完成了传球</p>
<p>使用了三个模型:xPass,传球类型的聚类,和OBV(控球价值?),其中:</p>
<ul>
<li>xPass 根据传球条件(例如起始位置、角度、对手压力和使用的身体部位)为我们预期传球完成频率提供了基准</li>
<li>传球聚类模型将具有相似特征的传球分组,使识别和分析比赛模式更加易于管理和解释</li>
<li>OBV 根据每个动作对球队得分和失球可能性的 +/- 影响来评估每个动作的模型</li>
</ul>
<p>接下来是一些结论</p>
<ul>
<li>总体来看,球场上最多的6种传球发生在中圈附近,以及传球到进攻三区的两侧,但 OBV 最高的传球是由后场边路发动的长传到进攻三区两侧,以及两侧传中球</li>
</ul>
<p>细分到位置:</p>
<ul>
<li>
后卫最常见的传球是从防守三区往中场的短传球,以及中圈附近的回传球,都是短传,通常是针对稳定的防守阵型,OBV 最高的传球是向前推进的传球,位置包含了左中右三条线,以及过了中圈的向前传球<ul>
<li>其中边后卫最有价值的是距离长的,从防守区域直接传到中场</li>
<li>中后卫则是距离较短的中路向前推进传球</li>
<li>以及高位的位置从中圈传到进攻三区中路,其中包括边后卫的向进攻肋部传球</li>
</ul>
</li>
<li>
中场最常见的传球是作为防守位置中圈附近回传球,作为中路进攻的进攻三区中路左右转移,以及进攻三区边路的渗透直传球,一个共同点是,所有人都以某种方式支持 build-on 阶段,并寻求在防守和进攻三区之间推进球,OBV最高的则是:<ul>
<li>边路中场需要的向禁区传中球,以及盘带到更靠近边路禁区线的短传传中</li>
<li>中路进攻的中路大禁区附近左右段距离横传</li>
<li>能够进入进攻区域并将球移到危险区域的中场球员平均而言将增加最大的价值</li>
</ul>
</li>
<li>前锋最常见的传球都在进攻三区,与中场球员类似,这也说明了现代足球的中场与前锋衔接很深,OBV 最高的传球一个有趣趋势是从边路传给防线后面的跑动者——这是快攻中非常有价值的传球</li>
</ul>
</content>
</entry>
<entry>
<title>《挪威的森林》一些补充</title>
<link href="https://tanzhijian.org/posts/norwegian_wood_2"></link>
<id>1727081794.3264656</id>
<updated>2024-09-23T16:56:34Z</updated>
<published>2024-09-23T16:56:34Z</published>
<author><name>tanzhijian</name></author>
<summary>我一直说《挪威的森林》是我极度偏爱的一部小说,但最近却发现,我未必真正读懂了这部小说,究其根本是我大概忽略了这部小说一个非常重要的东西,它的时代背景和它的时间线。我生活的世界没有对立,没有冲突,只有越来越潜移默化的美国现代自由主义,以及越来越正确的循规蹈矩,使得我理所当然的认为这个世界从古至今都应该是这样的形态,以至于对于每个时代的差异性缺乏必要的敏感。
</summary>
<content type="html">
<h1>《挪威的森林》一些补充</h1>
<p>我一直说《挪威的森林》是我极度偏爱的一部小说,但最近却发现,我未必真正读懂了这部小说,究其根本是我大概忽略了这部小说一个非常重要的东西,它的时代背景和它的时间线。我生活的世界没有对立,没有冲突,只有越来越潜移默化的美国现代自由主义,以及越来越正确的循规蹈矩,使得我理所当然的认为这个世界从古至今都应该是这样的形态,以至于对于每个时代的差异性缺乏必要的敏感。</p>
<p>然而这个世界的每个阶段都是巨大的差异,就像这本书对于现代不能接收的过多性描述,或许只是真实呈现那个年代的性解放思潮——一九六零年代。村上春树的青年完整跨越了那个年代,于是他写了这部小说,来记念一些人和事,在书的开头和后记体现的很明显:“献给许许多多的祭日”(这次读的赖明珠翻译的台版,这句话应该是“献给许多的纪念日”,不过我更喜欢林少华那句也就是前者,所以在本文的引用中会换着来,大致以台版为主,不喜欢部分的引用林少华),“这本小说具有极重的私人性质”,“这本小说谨献给我几位已经死去的朋友,和几位继续活下去的朋友。”主题也就是如此,一九六零年代,有的人永远停留,有的人继续向前。</p>
<p>我想重新谈谈小说中的几个人物。</p>
<h2>敢死队,永泽</h2>
<p>把这两个人放一起,是因为他们都不属于这个年代,换句话说他们可以是任何年代的人,或多或少在身边会见到的人,敢死队看似和周围所有人格格不入,周围人也常常以取笑他为乐,但却印证了这样的人,有着绝对的独立人格,不为周围环境所动,不为人们言语所动,而主角,也从一次又一次的嘲笑中获得了反思,也许他更该羡慕的是敢死队:“但老实说把他当做笑话题材我并不觉得多好受。他只是在不太富裕的家庭长大,排行老三,有点过于认真的孩子而已。而且只有制作地图是他小小人生中的小小梦想。谁能把那当笑话呢?”</p>
<p>永泽属于绝对意义上自私的人,一个利己主义者,却是一个很不错值得交的朋友,正直,对自己的过失或缺点总会确实承认。对于事物均有着强烈的个人见解,气度非凡:“人生中无需那种东西,需要的不是理想,而是行为规范!”“毕业后进入外务省施展自己的一番拳脚,想看看自己在这臃肿庞大的官僚机构中能爬到什么地步”。但同时他并不在乎周围任何人对他的影响,朋友,情侣,亲人,对于他来说在不涉及利益关系的前提下一切如常,否则只考虑自己——他只会在付钱的场合提起父亲,在约主角一同出游时可以很随意的抛弃,至于对初美,</p>
<blockquote>
<p>“那是初美的问题,不是我的问题。”</p>
</blockquote>
<blockquote>
<p>“换句话说我并不打算跟谁结婚,这件事我已经跟初美明白讲清楚过。所以,初美可以跟别人结婚。我不会阻止噢。”</p>
</blockquote>
<p>他不愿意别人成为他人生目标中的障碍,以至于当初美死去后他表现出的冷漠,让主角彻底抛弃了这个朋友。</p>
<h2>小林绿子</h2>
<p>在很多人的解读中,绿子是不折不扣的属于这个时代的嬉皮士,可以很随心所欲向任何信任的人表达爱与恨,也有时常挂在嘴边的 love and peace,对于那个年代所有的政治运动都不感兴趣:</p>
<blockquote>
<p>“嘿,我知道,因为我是平民。不管会不会发生革命,所谓平民都不得不在不怎么样的地方继续庸庸碌碌地活下去。革命算什么?那只不过像人到户政事务所去改个名字一样嘛”</p>
</blockquote>
<p>但她不是嬉皮士,真正的嬉皮士会随着这个年代一起消亡,而绿子对生活有无比的热情,他会照顾病重的父亲,从不流露出消极情绪,对于生活琐碎之事也会十分在意,他只是这个年代的一个普通的女生。当主角需要走出来的时候,会写到她。她也可以属于任何时代,一个真正关心生活,乐观轻松的人。</p>
</content>
</entry>
<entry>
<title>《La Roja》读书笔记</title>
<link href="https://tanzhijian.org/posts/la_roja"></link>
<id>1726823012.0323825</id>
<updated>2024-09-20T17:03:32Z</updated>
<published>2024-09-20T17:03:32Z</published>
<author><name>tanzhijian</name></author>
<summary>最近报名了一个网课,大概需要一些西班牙足球的历史知识,但我对此知之甚少,也不会西语,甚至不了解西班牙,但事已至此只能赶鸭子上架,求助了同期一位精通西班牙的香港大姐,推荐了《La Roja》,她的原话是“完美了解西班牙足球历史的入门读物,且不失深度。”
</summary>
<content type="html">
<h1>《La Roja》读书笔记</h1>
<p>最近报名了一个网课,大概需要一些西班牙足球的历史知识,但我对此知之甚少,也不会西语,甚至不了解西班牙,但事已至此只能赶鸭子上架,求助了同期一位精通西班牙的香港大姐,推荐了《La Roja》,她的原话是“完美了解西班牙足球历史的入门读物,且不失深度。”</p>
<p>于是便囫囵吞枣读了起来,由于这几天还需要抱其它佛脚,以至于读的快且不深,很多不太明白的也懒得查证。以下是些整理摘录的一些有意思的东西。说的不好或不对的请无视。</p>
<p>b站up足球司机韩在<a href="https://www.bilibili.com/video/BV16i421h752">西班牙足球真相研究</a>这期节目的一个结论很有意思:“散装西班牙”。</p>
<blockquote>
<p>“西班牙人民的基本特征之一是他们没有能力或不愿意为共同利益集中精力,他称之为“不合并”倾向。福特写道:“今天的西班牙一如既往,是一团用沙绳绑在一起的小团体,而且没有团结……”。 。 。也没有凝聚力。”</p>
</blockquote>
<blockquote>
<p>“在工业化的推动下,欧洲的共同经历是一个国家内部不断发展的不同社会和明显不同的变化速度。西班牙的特点是行动迟缓、发展零星。从更普遍的层面来看,与北欧不同,西班牙缺乏根深蒂固的中产阶级,这就消除了提炼贵族品味或提炼和淡化原始大众品味的渠道。西班牙是一个弗拉门戈、宗教节日和斗牛等流行艺术取得胜利并经久不衰的国家。”</p>
</blockquote>
<blockquote>
<p>“1912 年,Español 成为西班牙国王阿方索十三世授予皇室赞助的西班牙俱乐部之一,并有权在其名称中添加“Real”一词,并在其颜色上加冕皇冠。其他在西班牙体育界获得同样荣誉的球队包括皇家马德里、皇家社会、皇家塞尔塔维戈俱乐部、皇家伊伦联盟俱乐部、皇家马略卡体育俱乐部以及皇家贝蒂斯俱乐部。国王似乎旨在通过跨地区扩大对这项运动的赞助来扩大他的知名度”</p>
</blockquote>
<blockquote>
<p>“但西班牙就是西班牙,皇家马德里和西班牙人的王室任命只会加剧地区政治对抗和激烈竞争,而这种对抗将持续下去。”</p>
</blockquote>
<h2>La Furia, 皇家马德里</h2>
<p>西班牙足球的大部分历史不可避免地是由巴塞罗那足球俱乐部和皇家马德里足球俱乐部的竞争所推动的——它的政治、它的球员、它的权力、它的体育场、它庞大的球迷基础。</p>
<blockquote>
<p>“La Furia Española——一种特别强健和侵略性的足球风格,拥有高贵的意图和执行力,巴斯克人在俱乐部层面已经声称拥有名称版权,但它被吸收到更广泛的民族心理中。”</p>
</blockquote>
<blockquote>
<p>“奇怪的是,首次使用“La Furia”一词的记录并不是出现在任何西班牙媒体上,而是出现在一家荷兰报纸上,该报纸在西班牙胜利后的第二天进行了报道,并类比了西班牙帝国士兵在洗劫和掠夺敌人时所使用的可怕战术。”</p>
</blockquote>
<blockquote>
<p>“西班牙军国主义报纸《Arriba》引领了媒体的反应:“西班牙的愤怒终于卷土重来了。这场胜利向世界证明,只要充满激情、侵略性、勇气和阳刚之气,西班牙之怒——La Furia——是所向无敌的。”</p>
</blockquote>
<blockquote>
<p>“西班牙足球有一个前前后后的时期,这是由圣洛伦索之行所描绘的。这位阿根廷冠军留下了深刻的印记。 。 。这是一种精心设计的短传、三角站位足球,与西班牙更直接的足球形成鲜明对比,在西班牙,谈论战术被认为是异端邪说。阿根廷人相信要充分利用球和策略——面对这种情况,西班牙人只能用 La Furia 和即兴发挥来应对。”</p>
</blockquote>
<p>这个词伴随着西班牙战争及独裁者的落幕,最终也走向了它的下一步:</p>
<blockquote>
<p>“国家队现在充满了外国人,并且受到外国战术的影响,以至于它不再像一支真正的西班牙人队那样踢球,充满激情,充满侵略性,充满勇气,充满男子气概,最重要的是充满愤怒。”马卡报说。”</p>
</blockquote>
<blockquote>
<p>“1966 年世界杯之后,出现了一些伟大的国家队,如巴西、阿根廷、意大利和德国,潜力巨大。一路上我们运气不好,但事实是其他球队比我们好;他们受过更好的训练,拥有更新鲜的视野。我知道这个政权喜欢谈论“La Furia”,但这个词是一些记者发明的,而不是球员发明的。我们缺少的不是愤怒,而是一种清晰的风格、一个模型——一个系统。”</p>
</blockquote>
<blockquote>
<p>“那一代皇马球员最有效地表达了La Furia精神”</p>
</blockquote>
<blockquote>
<p>“在西班牙,皇马的球员们往往沉迷于斗牛形象,劳尔是最后一位伟大的斗牛士。图腾,代表了《La Furia》的精髓,在《La Furia》中,理想的球员“was both matador and toro bravo”(这句话我不会翻。。。),在追击对手时无所畏惧,在杀戮时冷酷无情、毫不妥协。”</p>
</blockquote>
<h2>战争,独裁者</h2>
<blockquote>
<p>“然而到那时,再多的庆祝活动也掩盖不了西班牙正处于解体边缘的事实,左翼和右翼不相容的政治在暴力日益增加的背景下失控走向内战。”“7月18日,军事起义开始,这个国家的失败、分裂和挫折的历史催生了其最终的绝望——西班牙内战。”</p>
</blockquote>
<blockquote>
<p>“有一段时间,足球在西班牙的一些地区被证明是一种社会缓和剂,是内战中为数不多的参与者互相尊重的公共行为之一。”</p>
</blockquote>
<blockquote>
<p>“事实上,内战意味着个别足球运动员不再因其技能而受到任何一方的尊重,而是根据他们被认为站在政治分歧的哪一边而受到支持或谴责。这将对西班牙足球的发展造成长期损害”</p>
</blockquote>
<blockquote>
<p>“他利用加泰罗尼亚人的政治混乱进行分裂和统治,其中许多人在内战中为他而战。他的目的从来不是阻止巴萨赢得冠军,而是希望看到西班牙足球由于两支伟大俱乐部的竞争而成为一项越来越受欢迎的运动。”</p>
</blockquote>
<blockquote>
<p>“在 20 世纪 50 年代,西班牙国家队的成绩持续不佳,西班牙在国际上仍然相对孤立,但令巴萨支持者懊恼的是,皇家马德里在海外帮助宣传了西班牙成功的形象。圣地亚哥·伯纳乌俱乐部实际上将自身与移民和橙子一起转变为佛朗哥最重要的出口产品。由于这一时期足球电视转播跨越国界,皇马成为了西班牙足球最佳代表,其外籍球星和本土天才混合在一起,踢出富有创意的进攻性足球。世界上没有其他俱乐部可以匹敌。”</p>
</blockquote>
<h2>南美,克鲁伊夫,巴塞罗那</h2>
<p>我一直在寻找一个西班牙现代足球注重技术,注重球商的线索</p>
<blockquote>
<p>“来访者都被东道主高超的风格和技巧所折服。阿根廷人展示了 Tique-taca 足球的非凡表现:控制、控球以及快速、短距离的传球”</p>
</blockquote>
<blockquote>
<p>“拉丁美洲人对西班牙足球的早期影响具有神奇的品质,近乎梦幻。然而,所涉及的技能是足够真实的,并预示着西班牙俱乐部足球的一些伟大人物,从迪斯蒂法诺到马拉多纳和罗纳尔多,以及后来的莱昂内尔·梅西。”</p>
</blockquote>
<blockquote>
<p>“但如果说西班牙足球有一种风格在新千年形成并取得了辉煌,那么克鲁伊夫就是播下了一些重要种子的人。”</p>
</blockquote>
<blockquote>
<p>“我喜欢基于足球的位置的进攻,我喜欢看到球队主宰局势。 。 。 。 “另一种”游戏规则基本上是:打长传,拦截,然后从那里交换球权。这是一种不同的方法,但我认为我的方法可以发挥个人技能。”</p>
</blockquote>
<blockquote>
<p>“克鲁伊夫谈到自己时说,他直到三十岁才明白为什么他会用足球做这些事情。从那时起,他一生的大部分时间都用他的足球哲学来激励他人。作为巴塞罗那足球俱乐部的教练和瓜迪奥拉的导师,克鲁伊夫理所应当地宣称自己拥有俱乐部的黄金岁月,并为西班牙足球界树立了一个值得效仿的榜样。”</p>
</blockquote>
<blockquote>
<p>“克鲁伊夫认为这样的制度破坏了俱乐部的集体认同感,并且不适应加泰罗尼亚的社会和文化背景。他从自己作为一名球员的经历中学到了足够多的东西,想要纠正它。毕竟他来自荷兰,一个长期以来一直激发年轻人才的足球国家。因此,他专注于鼓励新一代的巴萨球员,他们正在接受俱乐部的青训计划,并将他们融入到拥有高素质巴斯克球员和少量外国球星的球队中。这样的举措有助于西班牙足球的全面复兴。”</p>
</blockquote>
<blockquote>
<p>“La Roja 将旧时具有破坏性和消极性的 La Furia 转变为像葡萄酒甚至血液一样重要但更能赋予生命的东西,”</p>
</blockquote>
<blockquote>
<p>“西班牙队的比赛充满了英格兰队自初到以来就一直表现出的快节奏的阳刚之气,但他们的技巧和创造力也多年来在横渡大西洋的过程中展现出来”</p>
</blockquote>
<blockquote>
<p>“它的诞生也归功于一代年轻且极具天赋的西班牙球员,他们适应了 tique-taka 风格,在这种风格中,传球、耐心和控球从来没有达到缓慢、无方向的极端,而是构成了丰富的进攻编排的一部分,赢得足球,由伊涅斯塔和哈维等人组建的中场,比利亚和托雷斯等球员在其中发挥着先锋作用。”</p>
</blockquote>
<blockquote>
<p>“拉玛西亚是巴萨版足球基地的璀璨明珠,这是西班牙资金雄厚、组织完善的国家足球训练计划。学习曲线在海滩、社区街道和荒地的早期踢球中开始形成,但随着孩子们在小学及以后的激烈竞争的足球比赛中不断进步,俱乐部球探联系老师,寻找那些在十几岁的时候就有成为顶级专业人士的真正潜力。”</p>
</blockquote>
</content>
</entry>
<entry>
<title>一个感动的创业故事</title>
<link href="https://tanzhijian.org/posts/a_good_story"></link>
<id>1726251820.5937457</id>
<updated>2024-09-14T02:23:40Z</updated>
<published>2024-09-14T02:23:40Z</published>
<author><name>tanzhijian</name></author>
<summary>我曾经在《Football Hacker》这本书的读书笔记中分享过这个故事,但我想有必要再分享一次。这次会添加一些润色,以及一些主观的评述,如果想要了解更为真实的故事请直接阅读《Football Hacker》的第五章 outsiders。
</summary>
<content type="html">
<h1>一个感动的创业故事</h1>
<p>我曾经在《Football Hacker》这本书的读书笔记中分享过这个故事,但我想有必要再分享一次。这次会添加一些润色,以及一些主观的评述,如果想要了解更为真实的故事请直接阅读《Football Hacker》的第五章 outsiders。</p>
<h2>1.</h2>
<p>想成为比利·比恩的人。</p>
<p>克里斯·安德森这个名字大家可能会陌生,他写过一本《数字游戏:关于足球,你全弄错了……吗?》的书,是为数不多被翻译成中文的足球数据类书籍,他是康奈尔大学教授,教授政治经济学和政治社会学,原本平淡稳定且体面的生活。</p>
<p>但一切在 2009 年因为一本书而改变了,Moneyball。他的妻子是一名经济学家,她经常用这本书来教她的学生“基于证据的决策”,而她把这本书带给了他。其中的故事——棒球俱乐部董事总经理比利·比恩,巧妙地使用数据来克服他低预算的限制,投入了大量工作来寻找具有更强意义的新数据集,深深吸引了他。以至于读完后他发出感叹:“足球界的比利·比恩出现了吗?”</p>
<p>在 Moneyball 的兴趣推动下,他开始在互联网上搜索免费可用的比赛数据。他把数据下载到 Excel 表格中,并探讨相关性。</p>
<p>起初这只是一点乐趣,一个四十多岁的人的爱好,他已经在学术和个人生活中实现了他想要的东西。只有少数人对他的经验分析感兴趣,但随着愈发深入,他作为社会科学家在“日常工作”中使用的分析工具可以轻松应用于足球数据,越多的人开始成为他的读者,他开始逐渐明确了一个理想:“成为足球的比利·比恩。“</p>
<h2>2.</h2>
<p>他们住在纽约州的大学城伊萨卡,有红砖建筑、修剪整齐的草坪和古树,像明信片图片一般的校园。这是一个贵族和阶级的地方,但几乎不具备发动足球革命的自然基础。他们——他和他的妻子莎莉,需要一个好的计划。</p>
<p>在他们看来有两个因素是决定性的:他需要被认真对待;他必须想出一些真正改变比赛的东西,具有破坏性和令人印象深刻性,足以让潜在客户为此支付高额资金。</p>
<p>他们决定先写一本书,“首先,它使我们能够进行广泛的研究,使我们能够更好地了解该行业、其人员及其动态。它还让我有机会向这些人证明数字可以显示非常有趣的东西。”</p>
<p>他联系了 Opta 和 Prozone 等体育数据公司免费使用他们非常昂贵的数据,并承诺在书中对其价值进行宣传,他去了英国和德国的俱乐部,了解他们如何使用数据,2013 年书完成了,就是前面提到的《数字游戏》。他们选择了首先在英国出版,如果在美国出版,就会变成一本“来自美国的足球书籍”,天生得不到重视。</p>
<p>它于 2013 年发行,取得巨大成功,在英国、美国、斯堪的纳维亚半岛和一些亚洲国家拥有众多读者。他们计划的第一部分已经完成。人们确实认真对待他们,他们收获了一个有用的联系网络。</p>
<h2>3.</h2>
<p>但尽管如此,想要进入真正的足球圈仍然很远,数据分析部门很难得到自己俱乐部的赏识。“人们对这些新技术很感兴趣,但仅此而已。”“那里没有任何真正适合技术发展的环境;其中许多只是独自一人在推动,然后慢慢死去。”他们几乎可以确定,许多较大的俱乐部,特别是英超俱乐部,确实投资了技术球探或数据分析师。但他们中的许多人似乎被录用只是因为他们的老板不想被指责为过时。在决策过程方面,这些人的工作充其量只是次要的作用。</p>
<p>如果影响不到上层的决策,就不会产生任何影响。</p>
<p>这一认知导致他们得出了一个根本性的结论,试图说服俱乐部老板采纳他们的想法是没有意义的。他们必须找到愿意购买俱乐部的投资者,并从一开始就以不同的方式管理它。作为两位常春藤联盟教授,他们利用他们的联系人向来自中东、俄罗斯,当然还有来自美国的高净值企业家推销他们的愿景。</p>
<p>他们通过了多次的谈判,多次失败的接触,最终敲定了考文垂,获得了专业足球俱乐部的实践机会。</p>
<h2>4.</h2>
<p>可能到了这里,大家认为一切走向正轨,他们改造球队成功,一个完美的创业故事。但生活中失败与妥协才是常态,你不能像一个将军一样吠叫着命令,更多时候得像一个值得信赖的中尉知道如何在实地完成工作。票务,薪水,更衣室,甚至洗衣房,都需要妥善的处理,而他们并没有办法做好一切,这些才是俱乐部的真实面貌——数据战术只是很小的一部分。</p>
<p>他们于 2015 年接任,俱乐部以第八名结束了本赛季。第二年夏天,便出现了问题——他们认为他们无法解决这些问题。2016年10月,在工作一年多一点后,他们决定认输并离开。</p>
<p>所以这是一个失败的故事吗?</p>
<p>他们发现到目前为止,足球创新完全是由内部人士推动的。他们想创新也可以来自外部的想法,他们想试试局外人是否也能赢,这个想法非常浪漫。</p>
<p>在考文垂之前他成立了一家咨询公司 Anderson and Sally,就经济和金融问题向足球俱乐部的投资者提供建议,尤其是希望其中一位投资者有足够的勇气,把钱花在局外人身上。</p>
<p>他们仍然有退路,2018 年,他们接受了沃里克大学的聘书,回到了经济学和政治学教授的学术生活。他们仍然为足球俱乐部做一些咨询。</p>
<p>所以他们是幸运的,比起大多数我认识的,包括我自己。</p>
<p>这个故事发生在大约十年前,而到了现在,整个行业对于足球的核心圈,仍然是局外人。上层人士痴迷于他们的主观判断,似乎只有需要数据去解释他们的观点时才会引用,而从业者只能在长期不被认可的环境中摸索前行,足球作为一个古老行业,有着太多历史遗留问题。</p>
<p>但愿大家能在不具有包容性的时代,找到属于自己的角色。</p>
<p>也许,只是也许......</p>
</content>
</entry>
<entry>
<title>zed 的使用体验</title>
<link href="https://tanzhijian.org/posts/zed_explore"></link>
<id>1724056563.0601559</id>
<updated>2024-08-19T16:36:03Z</updated>
<published>2024-08-19T16:36:03Z</published>
<author><name>tanzhijian</name></author>
<summary>最近 zed 发布了 linux 的版本之后一直想尝试一下,开坑新项目的时候直接上手使用了两天,说一下感受吧,由于项目是 python,所以只说 python
</summary>
<content type="html">
<h1>zed 的使用体验</h1>
<p>最近 zed 发布了 linux 的版本之后一直想尝试一下,开坑新项目的时候直接上手使用了两天,说一下感受吧,由于项目是 python,所以只说 python</p>
<p>登陆 GitHub 账户授权后可以同步配置,包括设置插件和主题,这属于基本功能了</p>
<p>内置了 GitHub Copilot,前面登陆账户后便可直接使用提示,与 vscode 代码提示部分体验无差,sublime text 这个功能是包装的 neovim 体验稍差,但也仅有这个功能,如果需要使用 copilot chat,需要单打开一个 vscode 当作聊天窗口使用</p>
<p>代码编辑体验,我的主力编辑器是 sublime text,官方比对 zed 快一些,但实际使用体验不到这么点渲染差距,但就论跟手程度,都比 vscode 要好,这也是我为什么长期只用 vscode 做一些边角料工作的原因,不够丝滑,在这一点 zed 和 sublime text 都很好</p>
<p>编辑器内置了 lsp,也就是写什么语言编辑器就会提示安装什么 lsp,python 是 pyright,根据提示安装好便可,同时扩展市场内有 ruff,安装后配置好便可有提示,这点体验与 sublime text 一样,功劳都是 lsp,有了这两个写 python 体验就已经很好了,但目前 zed 的 lsp 功能至少在 python 上面没有 goto definition,这一点非常影响体验,看到 issues 里面已经有很多提交,应该不久就会解决</p>
<p>扩展市场不够丰富,由于是新玩意,这一点跟进的不太足,大部分主流一点的扩展基本还好,但说一个小众需求,我需要一个快捷键选中当前括号内所有内容,编辑器没有内置这个快捷按钮,需要通过插件实现,sublime text 和 vscode 都有,还有主题我经常使用的 monokai pro 这种小众但还算主流的配色也还没有 zed 版本,只能等后续完善了</p>
<p>总的来说,这款编辑器的成熟程度已经无限逼近 sublime text,作为 sublime text 党已经感受到岌岌可危了,毕竟万物皆 rust 的加持下这款编辑器活跃程度只会暴涨,而 vscode 作为万能钥匙一样的存在,再加上 copilot 各种原生体验的加持,目前还不可能撼动</p>
</content>
</entry>
<entry>
<title>that-game 的可视化功能探讨</title>
<link href="https://tanzhijian.org/posts/that-game_visualization_explore"></link>
<id>1721825101.4856722</id>
<updated>2024-07-24T20:45:01Z</updated>
<published>2024-07-24T20:45:01Z</published>
<author><name>tanzhijian</name></author>
<summary>我发现 that-game 通过设计好的数据格式,或许可以很方便的完成各个级别的可视化
</summary>
<content type="html">
<h1>that-game 的可视化功能探讨</h1>
<p>我发现 that-game 通过设计好的数据格式,或许可以很方便的完成各个级别的可视化</p>
<p>文章只为探讨,所有的示例图都为引用的效果图,其具体功能还未实现</p>
<h2>Pitch</h2>
<pre><code class="language-python">pitch = Pitch(length=105, width=68)
pitch.show()
</code></pre>
<p><img src="https://mplsoccer.readthedocs.io/en/latest/_images/sphx_glr_plot_pitches_003.png" alt="" /></p>
<pre><code class="language-python">pitch = Pitch(length=105, width=68, vertical=True)
pitch.show()
</code></pre>
<p><img src="https://mplsoccer.readthedocs.io/en/latest/_images/sphx_glr_plot_pitches_009.png" alt="" /></p>
<p>这样可以很方便的预览设置的 pitch 是否与自己心目中的一样</p>
<h2>Location</h2>
<p>每一个单独的 Location 都可以单独的查看在 pitch 中的位置</p>
<pre><code class="language-python">location = Location(x=60, y=40, pitch=pitch)
location.show()
</code></pre>
<h2>Event</h2>
<h3>Shot</h3>
<p>可以预览单次射门的状况</p>
<pre><code class="language-python">shot = Shot(...)
shot.show()
</code></pre>
<p><img src="https://mplsoccer.readthedocs.io/en/latest/_images/sphx_glr_plot_shot_freeze_frame_001.png" alt="" /></p>
<h3>Pass</h3>
<p>可以预览单次 pass 的传球图,传球方,接球方,球的轨迹,穿过的球员(如果有)</p>
<h3>其他</h3>
<p>其他的一些 type 类我还没有写完,比如 duel, block, dribble, 都会以单点的形式在 pitch 上描绘</p>
<h2>Game</h2>
<p>可以从 game 的角度查看更多</p>
<h3>shots</h3>
<pre><code class="language-python">game = Game(...)
shots = game.shots()
shots.shotmap(selected='home')
</code></pre>
<p><img src="https://mplsoccer.readthedocs.io/en/latest/_images/sphx_glr_plot_scatter_008.png" alt="" /></p>
<h3>passes</h3>
<pre><code class="language-python">passes = game.passes()
passes.network(selected='home')
</code></pre>
<p><img src="https://soccermatics.readthedocs.io/en/latest/_images/Denmark.png" alt="" /></p>
<pre><code class="language-python">passes.passmap(selected='home')
</code></pre>
<p><img src="https://mplsoccer.readthedocs.io/en/latest/_images/sphx_glr_plot_lines_001.png" alt="" /></p>
<pre><code class="language-python">passes.passmap(id='66')
</code></pre>
<p><img src="https://soccermatics.readthedocs.io/en/latest/_images/TAA.png" alt="" /></p>
<h3>其他</h3>
<pre><code class="language-python">touches = game.touches()
touches.heatmap(selected='home')
</code></pre>
<p><img src="https://mplsoccer.readthedocs.io/en/latest/_images/sphx_glr_plot_heatmap_001.png" alt="" /></p>
<h3>games</h3>
<p>可以站在 games 集合的角度查看一些统计数据</p>
<pre><code class="language-python">games = Games(Game(...), Game(...), Game(...))
shots = games.shots()
shots.shotmap(team='liverpool')
</code></pre>
<p><img src="https://soccermatics.readthedocs.io/en/latest/_images/Liverpool_shot_map.png" alt="" /></p>
<pre><code class="language-python">touches = games.touches()
touches.countmap()
</code></pre>
<p>接下来就是设计好用的 api 和参数,以及具体代码实现。坑越挖越大了。</p>
</content>
</entry>
<entry>
<title>关于 that-game</title>
<link href="https://tanzhijian.org/posts/about_that_game"></link>
<id>1720540408.808278</id>
<updated>2024-07-09T23:53:28Z</updated>
<published>2024-07-09T23:53:28Z</published>
<author><name>tanzhijian</name></author>
<summary>我在一些足球事件的项目中大量使用了 [kloppy](https://github.com/PySport/kloppy), 也有一些项目使用了 [socceraction](https://github.com/ML-KULeuven/socceraction) 的 spadl,这两个都可以看成“标准化的足球事件数据结构”,也就是把各个数据源的事件数据读取成一个统一的数据结构,方便后面的一系列计算。
</summary>
<content type="html">
<h1>关于 that-game</h1>
<p>我在一些足球事件的项目中大量使用了 <a href="https://github.com/PySport/kloppy">kloppy</a>, 也有一些项目使用了 <a href="https://github.com/ML-KULeuven/socceraction">socceraction</a> 的 spadl,这两个都可以看成“标准化的足球事件数据结构”,也就是把各个数据源的事件数据读取成一个统一的数据结构,方便后面的一系列计算。</p>
<p>但他们各有各的不方便。socceraction 是基于 pandas,使用 pandera 预设一些字段,也可以做数据验证。既然本质上是个 pd.DataFrame, 就有着 df 不可避免的优点和缺点,数据科学家会很习惯他的操作,但在编写实际代码的时候缺乏很好的自动补全,类型推断,在提供的字段上面也偏少:</p>
<pre><code class="language-python">sbl = StatsBombLoader(root=data_path, getter="local")
df_games = sbl.games(competition_id=43, season_id=3).set_index("game_id")
game_id = 8657
df_teams = sbl.teams(game_id)
df_players = sbl.players(game_id)
df_events = sbl.events(game_id)
home_team_id = df_games.at[game_id, "home_team_id"]
df_actions = spadl.statsbomb.convert_to_actions(df_events, home_team_id)
</code></pre>
<pre><code class="language-python">df_actions.sample(5)
</code></pre>
<div>
<table>
<thead>
<tr>
<th></th>
<th>game_id</th>
<th>original_event_id</th>
<th>period_id</th>
<th>time_seconds</th>
<th>team_id</th>
<th>player_id</th>
<th>start_x</th>
<th>start_y</th>
<th>end_x</th>
<th>end_y</th>
<th>type_id</th>
<th>result_id</th>
<th>bodypart_id</th>
<th>action_id</th>
</tr>
</thead>
<tbody>
<tr>
<th>2307</th>
<td>8657</td>
<td>206ac85d-9b2d-475f-88c7-bc4ccc2738e7</td>
<td>2</td>
<td>2482.471</td>
<td>768</td>
<td>3308.0</td>
<td>50.3125</td>
<td>59.075</td>
<td>39.8125</td>
<td>64.175</td>
<td>21</td>
<td>1</td>
<td>0</td>
<td>2307</td>
</tr>
<tr>
<th>168</th>
<td>8657</td>
<td>5e1b54a1-a93b-4c78-a69f-4ed8c708dbd9</td>
<td>1</td>
<td>346.439</td>
<td>782</td>
<td>3101.0</td>
<td>43.3125</td>
<td>27.625</td>
<td>42.4375</td>
<td>28.475</td>
<td>21</td>
<td>1</td>
<td>0</td>
<td>168</td>
</tr>
<tr>
<th>938</th>
<td>8657</td>
<td>19d08ada-edbc-4fe6-bfd3-00aa03977447</td>
<td>1</td>
<td>1821.052</td>
<td>768</td>
<td>3468.0</td>
<td>98.4375</td>
<td>30.175</td>
<td>97.5625</td>
<td>30.175</td>
<td>21</td>
<td>1</td>
<td>0</td>
<td>938</td>
</tr>
<tr>
<th>2310</th>
<td>8657</td>
<td>fe9150f6-60d7-429b-8116-115f1b49a1b8</td>
<td>2</td>
<td>2489.351</td>
<td>782</td>
<td>3077.0</td>
<td>25.8125</td>
<td>65.025</td>
<td>31.9375</td>
<td>64.175</td>
<td>21</td>
<td>1</td>
<td>0</td>
<td>2310</td>
</tr>
<tr>
<th>903</th>
<td>8657</td>
<td>9f489405-7d17-4a0b-9c77-089c49e0b056</td>
<td>1</td>
<td>1770.533</td>
<td>782</td>
<td>3176.0</td>
<td>65.1875</td>
<td>4.675</td>
<td>65.1875</td>
<td>12.325</td>
<td>0</td>
<td>1</td>
<td>5</td>
<td>903</td>
</tr>
</tbody>
</table>
</div>
<p>读取过程稍显麻烦,一些在我看来的重要信息,比如 team,player,type, result, bodypart 等都是使用数字作为类别,不存在可读性,如果想要搞清楚数字代表的具体含义需要再调用一个函数:</p>
<pre><code class="language-python">from socceraction.spadl import results_df
results_df()
</code></pre>
<div>
<table>
<thead>
<tr>
<th></th>
<th>result_id</th>
<th>result_name</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>0</td>
<td>fail</td>
</tr>
<tr>
<th>1</th>
<td>1</td>
<td>success</td>
</tr>
<tr>
<th>2</th>
<td>2</td>
<td>offside</td>
</tr>
<tr>
<th>3</th>
<td>3</td>
<td>owngoal</td>
</tr>
<tr>
<th>4</th>
<td>4</td>
<td>yellow_card</td>
</tr>
<tr>
<th>5</th>
<td>5</td>
<td>red_card</td>
</tr>
</tbody>
</table>
</div>
<p>都是可哈希对象,其实可以使用字符串使其更具有可读性。而且 spadl 作为为这个库主要的目的,计算 xT, VAEP 的数据结构,支持的 type 也偏少。</p>
<p>kloppy 是则是使用了更为灵活的基于对象的数据模型,有更多的预设读取,如果你只是用他预设的数据源进行操作没什么问题,想更多的自定义操作,他的数据类使用 python dataclass,就没办法有很好的数据验证:</p>
<pre><code class="language-python">from kloppy.domain import Team, Ground
# 这个是正确输入
team = Team(team_id="ars", name="Arsenal", ground=Ground.HOME)
# 但即使输入一些错误的类型也不会有问题
team = Team(team_id=123, name=123, ground="HOME")
</code></pre>
<p>只能通过 mypy 之类的工具寄希望于代码执行之前检查类型,并不具有强制性。同时如果想自定义创建一个 EventDataset 需要太多步骤:</p>
<pre><code class="language-python">from kloppy.domain import (
BallState,
DatasetFlag,
EventDataset,
Ground,
KloppyCoordinateSystem,
Metadata,
Orientation,
Period,
PitchDimensions,
Player,
Point,
Provider,
ShotEvent,
ShotResult,
Team,
)
</code></pre>
<pre><code class="language-python">period = Period(id=1, start_timestamp=0.0, end_timestamp=2827.0)
team = Team(team_id="ars", name="Arsenal", ground=Ground.HOME)
team_2 = Team(team_id="che", name="Chelsea", ground=Ground.AWAY)
player = Player(player_id="saka", team=team, jersey_no=7, name="Bukayo Saka")
coordinates = Point(x=100, y=50)
event = ShotEvent(
event_id="1",
period=period,
timestamp=217.32,
team=team,
player=player,
coordinates=coordinates,
result=ShotResult.OFF_TARGET,
raw_event=None,
ball_state=BallState.ALIVE,
ball_owning_team=team,
related_event_ids=[],
state={},
qualifiers=[],
freeze_frame=None,
)
</code></pre>
<pre><code class="language-python">pitch_dimensions = PitchDimensions(x_dim=108, y_dim=68)
coordinate_system = KloppyCoordinateSystem(normalized=True, length=108, width=68)
metadata = Metadata(
teams=[team, team_2],
periods=[period],
pitch_dimensions=pitch_dimensions,
orientation=Orientation.ACTION_EXECUTING_TEAM,
flags=DatasetFlag.BALL_OWNING_TEAM,
provider=Provider.OTHER,
coordinate_system=coordinate_system,
)
</code></pre>
<pre><code class="language-python">custom_dataset = EventDataset(records=[event], metadata=metadata)
</code></pre>
<p>他在描述状态的时候用了大量的 enum,每一个都需要导入,以及确定每一个字段的含义。而我使用最不舒服的一点在构建 team 和 player,他在设计时使用了循环引用:</p>
<pre><code class="language-python">@dataclass
class Player:
team: "Team"
@dataclass
class Team:
players: List[Player] = field(default_factory=list)
</code></pre>
<p>可以读他源代码中读取 statsbomb 的一段:</p>
<pre><code class="language-python"> def create_team(lineup, ground_type):
team = Team(
team_id=str(lineup["team_id"]),
name=lineup["team_name"],
ground=ground_type,
starting_formation=starting_formations[lineup["team_id"]],
)
team.players = [
Player(
player_id=str(player["player_id"]),
team=team,
name=player["player_name"],
jersey_no=int(player["jersey_number"]),
starting=str(player["player_id"]) in player_positions,
position=player_positions.get(str(player["player_id"])),
)
for player in lineup["lineup"]
]
return team
</code></pre>
<p>循环引用有什么后果不多讨论,单从使用上来说,需要先创建 team,然后创建 player,把 team 塞到 player,再把 player 塞到 team。</p>
<p>在使用那么久之后,我还是想自己创建一个 Events 的数据格式,便写了 that-game。</p>
<p>我中和了上面两个库的特性,以及长期的使用习惯,that-game 需要有以下的特点:</p>
<ul>
<li>创建简单</li>
<li>方便计算</li>
<li>尽可能的扁平化</li>
<li>支持数据验证</li>
<li>支持类型推断</li>
<li>预设常用的数据源读取</li>
<li>方便导出为常用格式</li>
<li>方便不同的数据规格(主要是坐标)转换</li>
<li>兼容尽可能多的事件类型</li>
<li>方便不同数据源之间匹配和融合</li>
<li>可读性</li>
</ul>
<p>使用 pydantic 来创建数据类可以解决大部分,常用状态使用 typing.Literal 预设字段,既能很好的配合编辑器补全,也能通过 pydantic 进行输入验证。</p>
<p>在创建新对象的时候,可以导入每个数据类,嫌麻烦也可以这样:</p>
<pre><code class="language-python">from that_game import Shot
shot = Shot(
id="0001",
type="shot",
period="first_half",
seconds=62.0,
team={"id": "ars", "name": "Arsenal"},
player={"id": "a7", "name": "Bukayo Saka", "position": "FW"},
location={
"x": 100.1,
"y": 43.2,
"pitch": {"length": 108, "width": 68},
},
end_location={
"x": 108.0,
"y": 43.2,
"pitch": {"length": 108, "width": 68},
},
pattern="open_play",
body_part="left_foot",
result="saved",
)
</code></pre>
<p>每个数据源之间最大的差异便是坐标系统,使用球场长宽高不同,方向不同,如何方便的转换是一个很大的问题,that-game 的 Location 可以很直观方便的转换:</p>
<pre><code class="language-python">from that_game import Location, Pitch
location = Location(
x=0.4,
y=0.6,
pitch=Pitch(length=1, width=1),
)
# 只需要设定好新的 pitch 标准
pitch = Pitch(
length=100,
width=100,
length_direction="left",
width_direction="down",
)
location.transform(pitch)
print(location.x, location.y)
</code></pre>
<pre><code>60.0 40.0
</code></pre>
<p>我会在完善 Location 类后添加更多的预设 pitch,更加方便转换。</p>
<p>目前支持的 type 仅有 shot 和 pass,支持的数据源也仅是 statsbomb,同时还有一个 fusion-events 的调试项目,在这里可以通过网络请求获取一些网站,比如 understat 的 events 进行操作。之后的工作重点便是添加更多的事件类型,添加更多的事件状态,添加更多的字段,比如 shot 预设计算 distance 和 angle, 以及不断调整它们之间的兼容性,更多的 loaders。这个库的难点不在于复杂度,而在于取舍,和更方便的使用。大概会用一年的时间让他变得可用吧。</p>
</content>
</entry>
<entry>
<title>open-data events 文档笔记</title>
<link href="https://tanzhijian.org/posts/ope_data_events"></link>
<id>1719315575.7717075</id>
<updated>2024-06-25T19:39:35Z</updated>
<published>2024-06-25T19:39:35Z</published>
<author><name>tanzhijian</name></author>
<summary>原文档 pdf 不方便查阅特做整理, 机器翻译手动整理结构
</summary>
<content type="html">
<h1>open-data events 文档笔记</h1>
<p>原文档 pdf 不方便查阅特做整理, 机器翻译手动整理结构</p>
<p>v4.0</p>
<p>本文档描述了StatsBomb开放事件数据的JSON格式。</p>
<h2>Format</h2>
<p>data/events 目录中的比赛文件将采用 JSON 格式。文件名将采用 1234.json 格式,其中 1234 是比赛 ID。内容是一个包含两支球队的事件信息的数组。一些元素有子元素(通常是名称/ID 对)或子数组(这些将在文档后面详细介绍)。</p>
<ul>
<li>
<p>id: uuid, 每个事件的唯一标识符</p>
</li>
<li>
<p>index: int, 每场比赛中事件排序的序列符号。自增的整数</p>
</li>
<li>
<p>preiod: int, 时间戳对应的比赛部分</p>
<ul>
<li>1: 1st Half</li>
<li>2: 2nd Half</li>
<li>3: 3rd Period</li>
<li>4: 4th Period</li>
<li>5: Penalty Shootout</li>
</ul>
</li>
<li>
<p>timestamp: timestamp, 比赛中事件发生的时间,精确到毫秒。</p>
</li>
<li>
<p>minute: int, 事件发生时时钟上的分钟数。半场结束时重置为 45 分钟,加时赛开始时重置为 90 分钟。</p>
</li>
<li>
<p>second: int, timestamp 的第二部分</p>
</li>
<li>
<p>type: object, (id: int, name: str), event 事件类型的 ID/名称。</p>
<ul>
<li>42, Ball Receipt, 接到传球</li>
<li>2, Ball Recovery, 尝试夺回球权</li>
<li>3, Dispossessed, 球员被防守球员拦截而带球失败,因此丢失球权</li>
<li>4, Duel, 比赛中对立双方两名球员之间 50 对 50 的较量</li>
<li>5, Camera On, 发出信号停止摄像机捕捉比赛过程以进行重播/视频剪辑</li>
<li>6, Block, 站在球的路径上阻挡球</li>
<li>8, Offside, 越位。由射门或解围(非传球)导致的事件。对于造成越位的传球,请查看传球部分</li>
<li>9, Clearance, 防守球员为消除危险而采取的行动,并非有意将球传给队友</li>
<li>10, Interception, 通过移动到传球路线/做出反应进行拦截,阻止对手的传球到达队友手中</li>
<li>14, Dribble, 球员试图带球突破对手</li>
<li>16, Shot, 用身体任何(合法)部位试图进球</li>
<li>17, Pressure, 对接球、带球或传球的对方球员施加压迫</li>
<li>18, Half Start, 裁判吹哨开始一个部分的比赛</li>
<li>19, Substitution</li>
<li>20, Own Goal Against, 对方球员的乌龙球</li>
<li>21, Foul Won, 犯规获胜的定义是,一名球员在遭到对方球员犯规后,为本队赢得任意球或点球</li>
<li>22, Foul Committed, 任何被裁判判为犯规的违规行为, 越位不被视为犯规</li>
<li>23, Goal Keeper, 守门员可以执行的动作</li>
<li>24, Bad Behaviour, 当球员由于比赛之外的违规行为而收到黄牌时</li>
<li>25, Own Goal For, 该队进了一粒乌龙球</li>
<li>26, Player On, 球员离开事件发生后,球员返回球场</li>
<li>27, Player Off, 一名球员未经替换就离开/被抬出球场</li>
<li>28, Shield, 球员保护出界的球以防止对手继续比赛</li>
<li>30, Pass, 球在队友之间传递</li>
<li>33, 50/50, 两名球员争夺无球权的球</li>
<li>34, Half End, 向裁判发出哨声,表示某一场比赛部分结束</li>
<li>35, Starting XI, 标明首发 11 名球员、他们的位置以及球队阵型</li>
<li>36, Tactical Shift, 表示球队的战术变化,显示球员的新位置和球队的新阵型</li>
<li>37, Error, 当一名球员被判定犯下控球失误,从而导致射门时</li>
<li>38, Miscontrol, 球员因触球失误丢球</li>
<li>39, Dribbled Past, 球员被对手带球突破</li>
<li>40, Injury Stoppage, 因受伤而停止比赛</li>
<li>41, Referee Ball-Drop, 因伤病暂停后,裁判放下球,继续比赛</li>
<li>43, Carry, 球员在移动或站立时控制脚下的球</li>
</ul>
</li>
<li>
<p>possession: int, 表示比赛中当前唯一的一次控球。一次控球表示在比赛期间,球处于比赛状态,并且由一支球队控制球</p>
</li>
<li>
<p>possession_team: object, (id: int), 开始控球的球队的 ID。请注意,即使在控球期间试图铲球等对手事件中,此 ID 也会显示</p>
</li>
<li>
<p>play_pattern: object, (id: int, name: str), 与此事件相关的比赛模式的 ID/名称</p>
<ul>
<li>1, Regular Play, 该事件不属于以下任何 play_patterns</li>
<li>2, From Corner, 该事件是角球之后比赛进程的一部分</li>
<li>3, From Free Kick, 该事件是任意球之后比赛过程的一部分</li>
<li>4, From Throw In, 此事件是界外球之后比赛过程的一部分</li>
<li>5, Other</li>
<li>
6, From Counter 该事件是反击的一部分:<ul>
<li>控球开始于反击球队最后三分之一区域外的一次常规比赛失误</li>
<li>控球至少有 75% 直接朝向球门(以我们的控球链指标衡量)</li>
<li>反击向球门前进了至少 18 码。</li>
<li>此定义不是收集的一部分,而是从上述逻辑中得出的</li>
</ul>
</li>
<li>7, From Goal Kick, 该事件是球门球后比赛过程的一部分</li>
<li>8, From Keeper, 这一事件是守门员开球后比赛进程的一部分</li>
<li>9, From Kick Off, 该事件是开球后比赛进程的一部分</li>
</ul>
</li>
<li>
<p>team: object, (id: int, name: str), 此事件所关联的球队的 ID/名称。仅当事件与特定球队相关时,才会显示对象</p>
</li>
<li>
<p>player: object, (id: int, name: str), 与该事件相关的球员的 ID/名称(仅当事件与特定球员相关时才会显示对象)</p>
</li>
<li>
<p>position: object, (id: int, name: str), 事件发生时球员所处位置的 ID / 名称</p>
<ul>
<li>1, GK, Goalkeeper</li>
<li>2, RB, Right Back</li>
<li>3, RCB, Right Center Back</li>
<li>4, CB, Center Back</li>
<li>5, LCB, Left Center Back</li>
<li>6, LB. Left Back</li>
<li>7, RWB, Right Wing Back</li>
<li>8, LWB, Left Wing Back</li>
<li>9, RDM, Right Defensive Midfield</li>
<li>10, CDM, Center Defensive Midfield</li>
<li>11, LDM, Left Defensive Midfield</li>
<li>12, RM, Right Midfield</li>
<li>13, RCM, Right Center Midfield</li>
<li>14, CM, Center Midfield</li>
<li>15, LCM, Left Center Midfield</li>
<li>16, LM, Left Midfield</li>
<li>17, RW, Right Wing</li>
<li>18, RAM, Right Attacking Midfield</li>
<li>19, CAM, Center Attacking Midfield</li>
<li>20, LAM, Left Attacking Midfield</li>
<li>21, LW, Left Wing</li>
<li>22, RCF, Right Center Forward</li>
<li>23, ST, Striker</li>
<li>24, LCF, Left Center Forward</li>
<li>25, SS, Sencondary Striker</li>
</ul>
</li>
<li>
<p>location: array, (x: int, y: int), 包含两个整数值的数组。这些是事件的 x 和 y 坐标(仅当事件具有高度坐标时才显示)</p>
</li>
<li>
<p>duration: float, 如果相关,则事件持续的时间(以秒为单位)</p>
</li>
<li>
<p>under_pressure: bool, 该动作是在对手施加压力的情况下做出的</p>
</li>
<li>
<p>off_camera: bool: 事件发生时,摄像机处于关闭状态</p>
</li>
<li>
<p>out, bool, 如果事件的结果是球出界,则添加</p>
</li>
<li>
<p>related_events: <code>array[uuid]</code>, 相关事件 ID 的逗号分隔列表。例如,射门可能与守门员事件和拦截事件相关。相应事件的 related_events 列中将包含射门的 ID</p>
</li>
<li>
<p>tactics: object</p>
<ul>
<li>formation: int, 对于“首发 XI 或战术换班”类型的事件,添加了“战术”对象。阵型项目描述了正在使用的阵型, 433</li>
<li>lineup: <code>array[player: object[id: int, name: str], position: object[id: int, name: str], jersey_number: int]</code>, 对于“首发 XI 或战术换人”类型的事件,添加了“战术”对象。阵容项描述了球员及其位置</li>
</ul>
</li>
</ul>
<h2>Event Type Objects</h2>
<p>如果事件属于具有附加详细信息的类型,则这些详细信息将嵌套在以该事件类型命名的对象中。例如,Shot 类型的事件将具有嵌套数据框,其中包含描述该事件类型的附加变量。以下是按字母顺序排列的嵌套数据框列表及其包含的变量。</p>
<ul>
<li>
<p>50-50</p>
<ul>
<li>
outcome: object, (id: int, name: str), 50 50争夺结果的ID/名称, values:<ul>
<li>108, Won</li>
<li>109, Lost</li>
<li>147, Success To Team, 球员赢得 50/50 并将球控制到己方</li>
<li>148, Success To Opposition, 球员赢得 50/50,但将球踢到对方</li>
</ul>
</li>
<li>counterpress: bool, 在 open play 转换后 5 秒内采取压迫</li>
</ul>
</li>
<li>
<p>Bad Behaviour: object, (id: int, name: str), 红黄牌的 ID/名称</p>
<ul>
<li>65, Yellow Card</li>
<li>66, Second Yellow</li>
<li>67, Red Card</li>
</ul>
</li>
<li>
<p>Ball Receipt: object, (id: int, name: str), 指定球接收结果的属性选项的 ID/名称</p>
<ul>
<li>9, Incomplete</li>
</ul>
</li>
<li>
<p>Ball Recovery
offensive: bool, 如果恢复进攻则添加
recovery_failure: bool: 如果恢复失败则添加</p>
</li>
<li>
<p>Block</p>
<ul>
<li>deflection: bool, 如果是偏转则添加</li>
<li>offensive: bool, 如果该阻挡具有攻击性则添加</li>
<li>save_block: bool, 如果阻挡了射门则添加</li>
<li>counterpress: bool, 在常规比赛转换后 5 秒内采取紧逼行动</li>
</ul>
</li>
<li>
<p>Carry</p>
<ul>
<li>end_location: array, (x: int, y: int)</li>
</ul>
</li>
<li>
<p>Clearance</p>
<ul>
<li>aerial_won: bool, 如果高空解围则添加</li>
<li>
body_part: object, (id: int, name: str), 触球身体部位的 ID/名称<ul>
<li>37, Head</li>
<li>38, Left Foot</li>
<li>40, Right Foot</li>
<li>70, Other</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Dribble</p>
<ul>
<li>Overrun: bool, 当球越过原来的防守队员进入另一名球员的球权时添加</li>
<li>Nutmeg: bool, 当球从对方球员腿间穿过时添加</li>
<li>
outcome: object, (id: int, name: str)<ul>
<li>8, Complete</li>
<li>9, Incomplete</li>
</ul>
</li>
<li>No Touch: bool, 如果球员试图通过将球漏过对手而不是接触球来进行带球</li>
</ul>
</li>
<li>
<p>Dribbled Past</p>
<ul>
<li>counterpress: bool, 在常规比赛转换后 5 秒内采取紧逼行动</li>
</ul>
</li>
<li>
<p>Duel</p>
<ul>
<li>counterpress: bool</li>
<li>
type: object, (id: int, name: str), Id/Name 为对抗的类型<ul>
<li>10, Aerial Lost, 争夺空中对抗但没能抢到球</li>
<li>11, Tackle, 抢断对方球员的控球权</li>
</ul>
</li>
<li>
outcome: object, (id: int, name: str), 对抗结果的 Id/名称<ul>
<li>1, Lost</li>
<li>4, Won, 抢断最终落入抢断队员手中</li>
<li>13, Lost In Play, 将球踢向对手的抢断</li>
<li>14, Lost Out, 铲球将球击出界外,有利于对手</li>
<li>15, Success</li>
<li>16, Success In Play, 将球传给队友的抢断</li>
<li>17, Success Out, 抢断将球击出界外,有利于抢断者的球队</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Foul Committed</p>
<ul>
<li>counterpress: bool</li>
<li>offensive: bool</li>
<li>
type: object, (id: int, name: str), Id/Name 为犯规的类型<ul>
<li>19, 6 Seconds, 因 6 秒违例被判犯规</li>
<li>20, Backpass Pick, 因回传用手接球违例被判犯规</li>
<li>21, Dangerous Play, 危险动作导致犯规</li>
<li>22, Dive, 因假摔而犯规</li>
<li>23, Foul Out, 因犯规被罚出场</li>
<li>24, Handball, 手球犯规</li>
</ul>
</li>
<li>advantage: bool, 如果裁判判定为进攻有利比赛继续则添加</li>
<li>penalty: bool, 如果被判点球添加</li>
<li>
card: object, (id: int, name: str), 卡牌的类型<ul>
<li>5, Yellow Card</li>
<li>6, Second Yellow</li>
<li>7, Red Card</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Foul Won</p>
<ul>
<li>defensive: bool, 如果在失去控球权的情况下犯规,则添加</li>
<li>advantage: bool, 如果裁判判定为进攻有利比赛继续则添加</li>
<li>penalty: bool, 如果判罚点球则添加</li>
</ul>
</li>
<li>
<p>GoalKeeper</p>
<ul>
<li>
position: object, (id: int, name: str), 守门员射门前站位选项的 ID/名称<ul>
<li>42, Moving, 射门时守门员正在移动</li>
<li>43, Prone, 射门时守门员倒在地上</li>
<li>44, Set, 射门时守门员处于静止状态</li>
</ul>
</li>
<li>
technique: object, (id: int, name: str), 守门员使用的技术技术选项的 ID/名称<ul>