بناء رسم متحرك متوسط ​​خط متحرك في R. استرداد البيانات من خلال NBA API

نواصل تحليل بيانات كرة السلة باستخدام R.


على عكس المقالة السابقة ، التي كانت مسلية بحتة ، قد تكون الرسومات التي سيتم بناؤها في هذه المقالة مثيرة للاهتمام من وجهة نظر تحليل لعبة الفريق في حملة الموسم.


وسوف نبني الرسوم البيانية لمتوسط ​​المتحرك لثلاثة أنواع من تصنيفات فريق الدوري الاميركي للمحترفين: الهجوم ، والدفاع ، والتصنيف الصافي (أي الفرق بين الأولين). باختصار عنهم. تصنيفات الهجوم والدفاع هي عدد النقاط التي سجلها الفريق أو افتقدها مقابل 100 ممتلكات. تصنيف صافي - وهذا هو الفرق لمائة الممتلكات. يمكن لأي شخص مهتم بمعرفة المزيد عنهم قراءة مسرد مرجع كرة السلة . هناك صيغة حسابية قمت بتطبيقها أيضًا باستخدام R ، لكنني لم أنشر بعد مقالًا عنها.


سأشرح أيضًا سبب بناء مخطط المتوسط ​​المتحرك. في كل مباراة فردية ، تكون نسبة العشوائية عالية جدًا ، حيث تقفز المؤشرات من 70 إلى 150 ، مما يجعل تحليل البيانات عديم الفائدة ، والرسم البياني نفسه يشبه رسم القلب. إذا أخذنا المتوسط ​​التراكمي ، فسنحصل على نقطة متطرفة أخرى: الجدول مشابه للتقلبات المخففة ، والألعاب في نهاية الموسم ، عندما يتم إضافتها إلى 70 إلى 75 مباراة بالفعل ، لا تؤثر عملياً على المؤشر الكلي. من الناحية التقريبية ، فهي "غير مرئية". المتوسط ​​المتحرك في هذه الحالة هو مخرج المأزق. من ناحية ، ينخفض ​​تأثير الصدفة ، من ناحية أخرى ، لا يوجد تراكم مفرط للنتائج. في إحصائيات كرة السلة ، عادة ما يقومون بمتوسط ​​متحرك لعشر مباريات.


المكتبات المستخدمة


library(httr) library(jsonlite) library(tidyverse) library(lubridate) library(zoo) library(ggthemes) library(gganimate) 

استرداد البيانات باستخدام NBA API


آخر مرة ، قمت باسترداد البيانات باستخدام ملحق NBA Data Retriever . هذه المرة سأستخدم واجهة برمجة تطبيقات NBA لتحميل البيانات المطلوبة مباشرةً إلى R.


أولاً نكتشف من أين يمكن الحصول على هذه البيانات. للقيام بذلك ، افتح الصفحة التي نحتاجها على stats.nba.com وانتقل إلى أدوات المطور. ثم افتح الشبكة -> XHR واضغط على F5. في القائمة التي تظهر ، نجد ملفًا باسم مشابه لاسم الصفحة. نحن بحاجة إليه. بعد التأكد من تحديد الملف الصحيح ، انسخ عنوانه في صفحة R. في الصور ، يبدو الأمر هكذا.


افتح الملف المطلوب



يجب أن يكون الملف مثل هذا



نسخ إلى عنوان R



الآن هيا بنا إلى العمل في R Studio . للحصول على المعلومات التي نحتاجها ، نستخدم وظيفة GET لحزمة http . ومع ذلك ، من أجل تنفيذ الطلب بشكل صحيح (يمكن التحقق من ذلك بواسطة لوظيفة status_code ، يجب أن يكون 200) ، تحتاج إلى إضافة رؤوس لتحديد معلمات العمل لمعاملة HTTP


 ##Adding headers request_headers <- c( "accept-encoding" = "gzip, deflate, sdch", "accept-language" = "en-US,en;q=0.8", "cache-control" = "no-cache", "connection" = "keep-alive", "host" = "stats.nba.com", "pragma" = "no-cache", "upgrade-insecure-requests" = "1", "user-agent" = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9" ) #Getting a response request <- GET(adv_box_team, add_headers(request_headers)) 

نحصل على إجابة مثل هذا:



لكن في حين أن البيانات التي نحتاجها غير مرئية. للحصول عليها ، نقوم أولاً باستخراج content الطلب من خلال content الوظيفة إلى ملف json ، ومن ثم تحويله إلى قائمة مع وظيفة من حزمة fromJSON باسم الحديث من fromJSON


 boxscore_data <- fromJSON(content(request, as = "text")) 

نتيجة لذلك ، نحصل على قائمة تحتوي بالفعل على جميع المعلومات التي نحتاجها ، ثم نضيفها ببساطة إلى الشكل المطلوب للعمل.


إعداد البيانات


للقيام بذلك ، قم بإنشاء جدول بيانات بدلاً من قائمة ، ثم قم بإضافة رؤوس الأعمدة.


 #Convert to tibble data and assigning column names table <- tbl_df(data.frame(boxscore_data$resultSets$rowSet[[1]], stringsAsFactors = FALSE)) names(table) <- toupper(boxscore_data$resultSets$headers[[1]]) 

toupper هي وظيفة تستبدل كل الحروف بأحرف كبيرة. بعد ذلك ، يجب أن نحصل على جدول به 2460 صفًا و 46 عمودًا. من حيث المبدأ ، يمكنك العمل مع الجدول في هذا النموذج ، ولكن من الأفضل استبعاد المعلومات غير الضرورية ، من أجل عمل أكثر ملاءمة وسرعة.


 ##Select the columns you want to analyze rating <- table %>% select(TEAM_ID, TEAM_ABBREVIATION, TEAM_NAME, GAME_ID, GAME_DATE, MATCHUP, WL, E_OFF_RATING, E_DEF_RATING, E_NET_RATING) 

إذا نظرت إلى الجدول المصدر ، يمكنك أن ترى نوعين من التصنيف نفسه: "عادي" ومع البادئة E. دون الخوض في التفاصيل ، يأخذ التصنيف الإلكتروني في الاعتبار سرعة اللعبة ، وبالتالي فهو أكثر دقة. نحن نأخذها.


بعد ذلك ، أريد أن أبسط أسماء التصنيفات. ستحتاج إلى إدخالها في وسيطات الوظائف ومن الأفضل استخدام الترميز الأكثر دراية لمجموعة واسعة من المستخدمين: ORTG ، DRTG ، NRTG. يمكنك هنا "الخلط" مع كتابة تعبير منتظم str_replace بـ str_replace ، لكن كتابتها لا تزال ممتعة ومن هنا يمكننا الاستغناء عنها تمامًا. نحتاج فقط إلى استخراج الأحرف 3 و 7 و 9 و 12 من الأسماء الحالية ، ودمجها واستبدال أسماء الأعمدة بموجه الأحرف الناتج. كل هذا يتم باستخدام وظائف الحزمة str_sub : str_sub و str_c (تناظرية paste0 الأساسي paste0 ).


 ## Renaming columns with E_OFF_RATING on ORTG rating1 <- rating %>% rename_at(vars(starts_with("E_")), list(~str_c(str_sub(., start = 3, end = 3), str_sub(., start = 7, end = 7), str_sub(., start = 9, end = 9), str_sub(., start = 12, end = 12)))) 

في وظائف الحزمة ، يحتوي dplyr على نفس خاصية بناء dt[, lapply(.SD, func), .SDols = col1] في الحزمة data.table : يتم تطبيق الإجراء على عدة أعمدة في نفس الوقت. نختار هنا جميع الأعمدة التي يبدأ اسمها بـ "E_".


نتيجة لذلك ، حصلنا على مثل هذا الجدول ، والذي سنواصل العمل معه:


TEAM_IDTEAM_ABBREVIATION يتفوقونTEAM_NAMEGAME_IDGAME_DATEتنافساWLORTGDRTGNRTG
1610612749MILباكز ميلووكي00218012262019-04-10T00: 00: 00ميل مقابل OKCL102.4116.8-14،4
1610612766CHAقرون شارلوت00218012222019-04-10T00: 00: 00CHA مقابل ORLL121.4130.1-8.6
1610612758SACملوك سكرامنتو00218012302019-04-10T00: 00: 00SAC @ PORL129.7136.4-6.8
1610612748MIAميامي هيت00218012212019-04-10T00: 00: 00MIA @ BKNL84.2103.6-19،4
1610612750MINمينيسوتا تمبروولفز00218012282019-04-10T00: 00: 00MIN @ DENL98.3103.7-5.4

وظيفة rolling_offnet_rating_nba للتخطيط وتحريك المتوسط ​​المتحرك.


مرة أخرى ، مثل آخر مرة ، لنقم بإنشاء وظيفة لإجراء تغييرات طفيفة في العمليات الحسابية.


rolling_offnet_rating_nba وظيفة rolling_offnet_rating_nba كما يلي:


 rolling_offnet_rating_nba <- function(table, name, variable, col1 = col1, col2 = col2) 

الجدول هو اسم جدول البيانات ،
الاسم - اختصار الفريق الذي سيتم إجراء الرسومات له ("BOS" ، "LAL" ، إلخ).
متغير - التصنيف الذي سيتم حسابه (فيما يلي خياران ، ORTG أو NRTG ، للتصنيف الوقائي الذي أدليت به وظيفة منفصلة)
col1 و col2 - لون الخط بقيمة أعلى / أقل من المتوسط.


تستخدم معظم وظائف dplyr غير قياسي (NSE ). هذا مصطلح عام يعني أن تقييمهم يختلف عن التقييم المعتاد في R. وهذا يسمح لنا بتبسيط كتابة التعليمات البرمجية والعمل مع قواعد بيانات SQL ، ولكن الطرح هو أنه لا يمكننا استبدال القيمة بكائن مكافئ معرف في مكان آخر.


يستخدم Dplyr تقييم مرتبة . لذلك ، من الضروري استخدام أدوات خاصة (وظائف الاستشهاد ، عامل التشغيل!) لحل المشكلات التي صودفت أثناء البرمجة. يمكنك قراءة المزيد عن هذا هنا ، ونرى هنا .


تأخذ التعليمة البرمجية التالية اسم وسيطة الدالة وتكتب التعبير الذي تم تقديمه إليها. (لفهم كيفية عمل enquo ووظائفه المشابهة ، من المفيد طباعة إخراج هذه الوظيفة)


 ##Return the entered value in the function argument in the type quosure quo_rating <- enquo(variable) quo_col1 <- enquo(col1) quo_col2 <- enquo(col2) 

بعد ذلك ، نقوم بتغيير تنسيق البيانات لبعض الأعمدة: نجعل GAME_DATE من عمود الأحرف في تنسيق التاريخ ، ونجعل أعمدة التصنيف رقمية. لأن نحن نطبق الدالة as.numeric على ثلاثة أعمدة ، ثم mutate_at استخدام mutate_at بدلاً من mutate_at . ونحن فرز كل شيء في ترتيب تصاعدي من التاريخ.


 ##Changing the data type of multiple columns test1 <- table %>% mutate(GAME_DATE = as.Date(ymd_hms(GAME_DATE))) %>% mutate_at(vars(ORTG:NRTG), list(~as.numeric)) %>% arrange(GAME_DATE) 

ثم نحسب المتوسط ​​المتحرك لعشر مباريات للفريق الذي نحتاج إليه. للقيام بذلك ، استخدم الدالة rollmeanr من حزمة zoo . r في نهاية الاسم تعني أن النتيجة يجب أن تكون محاذاة لليمين. بالنسبة للألعاب التسعة الأولى من الموسم ، من المستحيل حساب متوسط ​​متحرك لعشرة مباريات ، لذلك نترك هذه الحقول دون تغيير عن طريق ملؤها في NA باستخدام وسيطة التعبئة. na.omit يزيل من الجدول الصفوف التي تحدث فيها NA.


 ##The calculation of the moving average team <- test1 %>% filter(TEAM_ABBREVIATION == "DAL") %>% mutate(RATING = rollmeanr(ORTG, k = 10, fill= NA)) %>% na.omit(test1) 

طاولة الفريق تبدو كالتالي:


TEAM_IDTEAM_ABBREVIATION يتفوقونTEAM_NAMEGAME_IDGAME_DATEتنافساWLORTGDRTGNRTGRATING
1610612742DALدالاس مافريكس00218001502018/06/11دال مقابل WASW116.899.217.6105.51
1610612742DALدالاس مافريكس00218001602018/07/11DAL @ UTAL98.5112.0-13،6104.92
1610612742DALدالاس مافريكس00218001812018/10/11دال مقابل OKCW115.0101.113.9104.13
1610612742DALدالاس مافريكس00218001932018/11/12DAL @ CHIW98.391.07.3103.03
1610612742DALدالاس مافريكس00218002102018/11/14دال مقابل UTAW117.365.851.6105.34

من حيث المبدأ ، لقد تلقينا بالفعل المعلومات التي نحتاجها. باستخدام سطرين من التعليمات البرمجية ، يمكنك بناء رسم بياني خطي. لكن الخط الأسود الموجود على خلفية بيضاء ليس له أهمية كبيرة من الناحية الجمالية والإعلامية. جزء آخر من "نص الدالة" يصحح هذا.


بادئ ذي بدء ، نضيف البيانات في المتوسط ​​، والقيمة 10 و 21 (العاشرة من الأسفل) ، بالإضافة إلى تاريخ 10 من مباراة الفريق (على سبيل المثال ، الأول الذي يتم حساب المتوسط ​​المتحرك له والذي ظل في جدول الفريق بعد حذف الخطوط من NA) .


 ##The average, 10 and 21 ratings in the entire League. average <- league %>% mutate(average = mean(!! quo_rating)) %>% select(average) %>% unique() %>% .$average top10 <- league %>% arrange(desc(!! quo_rating)) %>% select(!! quo_rating) %>% slice(10) top10 <- top10[[1]] bottom10 <- league %>% arrange(desc(!! quo_rating)) %>% select(!! quo_rating) %>% slice(21) bottom10 <- bottom10[[1]] ##Getting the date of the first rollaverage data <- team %>% select(GAME_DATE) %>% arrange(GAME_DATE) data <- data[[1,1]] 

من الوظائف غير المستخدمة سابقًا ، تظهر وظيفة slice هنا ، والتي تحدد الصفوف حسب رقمها التسلسلي.


بعد ذلك ، نختار لونين واسمه. يتم أخذ البيانات ، مثل آخر مرة ، من الجدول table_color . سيتم استخدام الاسم في عنوان المخطط لتوضيح أي من الألوان يتوافق مع قيم أقل من المتوسط ​​وأيها أعلى.


 ##Getting color and color_name selected color color1 <- table_color %>% filter(TEAM_ABBREVIATION == name) %>% select(!! quo_col1) color1 <- color1[[1]] color2 <- table_color %>% filter(TEAM_ABBREVIATION == name) %>% select(!! quo_col2) color2 <- color2[[1]] name1 <- paste0("name_", quo_name(quo_col1)) name2 <- paste0("name_", quo_name(quo_col2)) name_color1 <- table_color %>% filter(TEAM_ABBREVIATION == name) %>% select(name1) name_color1 <- name_color1[[1]] name_color2 <- table_color %>% filter(TEAM_ABBREVIATION == name) %>% select(name2) name_color2 <- name_color2[[1]] 

الوسيطات الدالة الافتراضي ل col1 و col2 ، هذه هي الألوان الأولى والثانية للأوامر. في معظم الحالات (على وجه التحديد في 26) ، لا تحتاج هذه القيم إلى تغيير ، ومع ذلك ، بالنسبة لأربعة فرق ، يجب استخدام اللون التالي في لوحة الألوان الخاصة بهم. في دالاس ومينيسوتا ، تتشابه الألوان الأولى والثانية للغاية ، في حين أن ميلووكي وبروكلين غير مرئيتين على خلفية بيضاء. كلاهما ، وآخر يعقّد قراءة الجدول الزمني ، لذلك يجدر استخدام الوسيطة col2 = col3 لهم.


التالي نحصل على الحد الأقصى لتصنيف الفريق. سنحتاج إلى هذه القيمة لترتيب النص مع قيمة التصنيف على الرسم البياني. أريد الانتباه إلى السطر الأخير من التعليمات البرمجية. لقد حدث أن الوظائف رسمت الرسوم البيانية تماما في 89 من أصل 90 حالة ، ولكن عند بناء تصنيف الحماية ، أعطى ميلووكي خطأ. اتضح أن الحد الأقصى لقيمة التصنيف في ميلووكي يتحقق مرتين ويبدأ ggplot2 بشكل طبيعي أن يقسم أن الجمالية يجب أن تكون ، في حالتنا ، إما 1 أو 73. لذلك ، نحن بحاجة إلى قيمة تصنيف قصوى واحدة.


 ##The maximum value of the rating max <- team %>% filter(RATING == max(RATING)) %>% select(RATING) max <- max[[1]] 

بناء الرسم البياني ثابت في ggplot2


 ##Building and save a static chart Sys.setlocale("LC_ALL", "C") gg <- ggplot(team, aes(GAME_DATE, RATING)) + geom_hline(yintercept = c(top10, bottom10), col = c("red", "blue")) + annotate(geom = "text", x = as.Date(data) + 2, y = top10 - 0.2, label = "TOP 10", col = "red") + annotate(geom = "text", x = as.Date(data) + 2, y = bottom10 + 0.2, label = "BOTTOM 10", col = "blue") + geom_line(size = 2, col = if_else(team$RATING > average, color1, color2)) + theme_tufte() + labs(title = paste0(team$TEAM_NAME, " 10-Game Rolling ", quo_name(quo_rating)), subtitle = paste0(paste0(name_color1, " - above average ", quo_name(quo_rating)), "\n", paste0(name_color2, " - below average ", quo_name(quo_rating))), caption = "Source: BBall Index Data & Tools\nTelegram: @NBAatlantic, twitter: @vshufinskiy") theme(plot.title = element_text(size = 12, hjust = 0.5), plot.caption = element_text(size = 10), plot.subtitle = element_text(size = 9)) ggsave(paste0(unique(team$TEAM_NAME), quo_name(quo_rating), ".jpeg"), gg, width = 8, units = "in") 

من الجديد هنا ، استخدام الدالة if_else لتغيير لون الخط بناءً على ما إذا كان متوسط ​​تصنيف الدوري أعلى أو أقل ، وكذلك السطر الأول الذي يغير اللغة. يتم ذلك بحيث تتم كتابة الاختصارات الخاصة بأسماء الأشهر على طول المحور X باللغة الإنجليزية.


الرسوم المتحركة لمتوسط ​​المتحرك 10 مباريات.


في بناء الرسوم المتحركة ، أضفت عدة مستحضرات غير ممكنة في الإصدار الثابت. أولاً ، تاريخ التغيير (على غرار الطريقة التي تغيرت بها السنة في المقالة الأخيرة) ، وكذلك قيمة التصنيف في وقت معين من الزمن. يتغير أيضًا اللون حسب ما إذا كان أعلى أو أقل من المتوسط.


 ##Building animations anim <- gg + theme(plot.title = element_text(hjust = 0.5, size = 25), plot.subtitle = element_text(size = 15), plot.caption = element_text(size = 15), axis.text = element_text(size = 15), axis.title = element_text(size = 18)) + geom_text(aes(x = as.Date(data), y = max + 0.5), label = paste0(quo_name(quo_rating)," ", round(team$RATING, digits = 1)), size = 6, col = if_else(team$RATING > average, color1, color2)) + transition_reveal(GAME_DATE) + labs(title = paste0(team$TEAM_NAME, " 10-Game Rolling ", quo_name(quo_rating)), subtitle = paste0(paste0(name_color1, " - above average ",quo_name(quo_rating)), "\n", paste0(name_color2, " - below average ",quo_name(quo_rating)), "\n", "Date: {frame_along}"), caption = paste0("Source: stats.nba.com\nTelegram: @NBAatlantic, twitter: @vshufinskiy")) 

يؤدي



على الرسم البياني ، من الواضح أن دالاس انخفض في النصف الثاني من فبراير إلى مارس. التفسير لهذا بسيط للغاية: في هذه المرحلة من الموسم ، تبادل مافريكس 4 من أصل 5 لاعبين في بدايتهم الخمسة ، ولم يلعب الأصل القادم ، لاتفيا كريستابس بورزينجيس ، لدقيقة واحدة بسبب تمزق الرباط الصليبي.


لن أتطرق هنا إلى العنصر الرياضي ، لذا إذا كان أي شخص مهتمًا بمشاهدة الرسوم البيانية المتبقية البالغ عددها 89 مخططًا في موسم 2018-1919 ، فأنت مرحب بك في مدونتي على sports.ru ، حيث أخطط لكتابة مقال مع نظرة عامة على أكثرها إثارة للاهتمام أو في Telegram الخاص بي قناة عن الدوري الاميركي للمحترفين ، حيث سأقوم بنشرها جميعًا.


مستودع جيثب

Source: https://habr.com/ru/post/ar459142/


All Articles