当前位置: 首页>PHP>正文

英雄聯盟數據分析專題(三)

英雄聯盟數據分析專題(三)

寫在前面的話

在這里插入圖片描述
本次的主題是關于英雄聯盟的Tribunal法庭系統國服也叫做議事大廳。英雄聯盟議事大廳是為了解決騷擾投訴而設計的,讓所有擁有資格的玩家去評估每個被投訴者的案子。英雄聯盟議事大廳會提供每一位被舉報玩家的相關數據,審判者需要對內容進行仔細的判斷后,決定“懲戒”或“寬恕”被舉報的玩家。(摘自英雄聯盟國服官網)

在游戲中我們難免會遇到一些不太友好的玩家使用語言攻擊對手或隊友,而在結束游戲后針對言行過激的玩家大部分玩家都會使用舉報系統進行舉報。其中一些被舉報的案例會統一交由參與議事大廳的玩家來投票決定對被舉報采取何種處罰方式。本篇將使用的數據集正是這些有舉報行為的對局中的聊天記錄,雖然該數據集來自北美服務器,但我認為不同服務器玩家之間存在較大的共性,希望在閱讀過本文后讀者們對英雄聯盟中的玩家行為有更深刻的理解同時也能規范自己在游戲中的言行來創造更好的游戲環境。

背景介紹

該數據集包含了超過一萬場被舉報對局的聊天記錄,其中包含每場對局中十個玩家全部聊天記錄。且該數據集中的字段也非常豐富,共有9個字段,分別為:
message: 聊天記錄內容
association_to_offender: 與被舉報人的關系,分為敵方,隊友以及被舉報人
time: 聊天記錄發生時的游戲對局內時間
case_total_reports: 在該被舉報人被提交到議事大廳之前共被舉報次數
allied_report_count: 隊友中舉報該玩家人數
enemy_report_count: 對方中舉報該玩家人數
most_common_report_reason: 在最近5次被舉報對局中該玩家最常被舉報原因
chatlog_id: 聊天記錄對應ID(也可做為每場游戲對局的ID,相同游戲對局的每條聊天記錄ID相同)
champion_name: 每條聊天記錄對應的英雄名稱

從上面的介紹中可以看到該數據集的信息量非常大,有了豐富的數據集我們就可以從不同的維度來進行分析。

探索性數據分析

#導入本文中所有需要的庫
import pandas as pd
from nltk.tokenize import RegexpTokenizer
from collections import Counter
import operator
import re
import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import BernoulliNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt

首先我們載入數據集并對數據集做一些基本的處理。

#載入數據集
data=pd.read_csv('chatlogs.csv')
data=data.iloc[:,1:]
#查找數據集中缺失值
data.isnull().sum()

在這里插入圖片描述
從結果中可以看到message這一項有29個缺失值,association_to_offender中有104個缺失值, champion_name中有104個缺失值。因為我們關心的是被舉報人的聊天記錄所以association_to_offender這一項的缺失值對數據分析的影響最大,要先對該字段中的缺失值進行處理。在后面對數據集的應用中會針對每種情況對不同缺失值做相應的處理。

#刪除缺失值
data['association_to_offender'].dropna(inplace=True)
#打印數據框前十條記錄
data.head(10)

在這里插入圖片描述

#打印總游戲對局數
print('Number of chatlogs: {}'.format((data['chatlog_id'].nunique())))
#打印總聊天記錄數
print('Number of records: {}'.format(data.shape[0]))

在這里插入圖片描述
在這里插入圖片描述
該數據集中共包含10058場游戲對局其中有近170萬條聊天記錄。到這里讀者應該就對我們的數據集有了一個大致的了解。

因為我們拿到該數據集,最感興趣的還是被舉報玩家的行為,所以我們首先要把被舉報玩家的聊天記錄單獨提取出來。然后我首先想到的一個問題就是使用哪些英雄的玩家被舉報的次數更多呢?

#把被舉報玩家的聊天記錄提取出來
offender_df=data[data['association_to_offender']=='offender']
#計算每個英雄被舉報的次數
champion_counts=offender_df.groupby('champion_name')['chatlog_id'].nunique()
champion_counts=pd.DataFrame(champion_counts)
#對結果進行降序排列
champion_counts=champion_counts.sort_values(by='chatlog_id',ascending=False)
#打印排名前五的英雄和被舉報次數
print('5 most offensive champions:')
print(champion_counts.iloc[:5,:])
#打印排名最后五名的英雄和被舉報次數
print('5 least offensive champions:')
print(champion_counts.iloc[-5:,:])

在這里插入圖片描述
在這里插入圖片描述
通過結果可以看出,最常被舉報的英雄為盲僧,薇恩,伊澤瑞爾,銳雯和女警而最不常被舉報的英雄為維克托,蘭博,蝎子,加里奧和厄加特。但是英雄聯盟的老玩家可能會發現英雄被舉報的次數似乎和英雄本身的熱度有關,也就是說熱門的,人人都喜歡玩的英雄就會有更高的被舉報次數而一些比較冷門的英雄相對被舉報的次數就會變得很低。而且該數據集僅使用了約一萬場游戲來進行分析,所以具有一定的局限性和時效性。但是該結果也能說明一些問題,被舉報次數最多的前五名英雄都是一些操作上限較高的英雄,而相對應的使用這些英雄的玩家就有更高的可能因為隊友或對手的一些失誤而攻擊他們。

下面我們再來看看使用哪些英雄的玩家是話癆大王。

#計算每個英雄對應的聊天記錄數
chat_counts=offender_df.groupby('champion_name')['chatlog_id'].count()
chat_counts=pd.DataFrame(chat_counts)
#對結果進行降序排列
chat_counts=chat_counts.sort_values(by='chatlog_id',ascending=False)
#打印最話癆的五個英雄
print('5 most talktive offenders:')
print(chat_counts.iloc[:5,:])
#打印話最少的五個英雄
print('5 least talktive offenders:')
print(chat_counts.iloc[-5:,:])

在這里插入圖片描述
在這里插入圖片描述
這個結果和之前的排序稍有變動但英雄一致,在這里排序同樣受之前所提到的因素影響。但是值得注意的是,被舉報的盲僧玩家的聊天記錄數幾乎比第二名的薇恩玩家多出了3000條。我對國服的玩家不太了解但具我對美服玩家的了解這一結果還是很具有代表性的。這說明盲僧玩家不僅敢打敢操作而且在和隊友互動上也不落下風。

下面我們對被舉報玩家的聊天記錄內容來做分析。我很想知道那些被舉報的玩家最常說的詞是什么,也許就是這些詞導致了這些玩家被舉報。

#把message, chatlog_id, champion_name三個字段單獨提取出來做分析
offender_message_df=offender_df.loc[:,['message','chatlog_id','champion_name']].reset_index()
offender_message_df=offender_message_df.iloc[:,1:]
#刪除缺失值
offender_message_df.dropna(inplace=True)
#自定義一個函數
#該函數可輸出出現次數最多的k個詞
def getTopK(df, kwords, operation=operator.eq):counter = Counter()stop = set(stopwords.words('english'))messages=df['message'].valuesfor message in messages:counter.update([word.lower() for word in re.findall(r'\w+', message) if word not in stop and len(word) > 2])topk = counter.most_common(kwords)return topk
#打印出被舉報玩家聊天記錄中出現頻率最高的20個詞
getTopK(offender_message_df, 20)

在這里插入圖片描述
由于在自定義函數中已經刪去了停用詞所以結果中出現的詞都是具有一定代表性的有實際意義的詞。出現頻率最高的兩個詞’report’ 和 ‘noob’是美服中非常具有代表性的兩個詞。‘report’一般出現在當一名玩家對自己的隊友表現不滿意的時候就會發動隊友和對方來舉報自己的這名隊友,而’noob’這個詞是本來是菜鳥的意思但在美服英雄聯盟玩家的’口‘中這個詞的程度還要比菜鳥更深,有點類似于國服中經常指責隊友菜時出現的詞語,讀者可以自行腦補。而且這個結果中還有一個非常有意思的一點就是’mid’, ‘bot’, 'top’這三個單詞,出現的次數相差不大而且排列在一起,這是不是說明打野玩家指責隊友的概率更大呢?

對整體的情況做了分析之后我突然想到如果對被舉報次數最多和最少的英雄分別做以上分析,會不會發現一些有趣的東西呢?

#提取出被舉報的盲僧玩家的聊天記錄
leesin_message_df=offender_message_df[offender_message_df['champion_name']=='Lee Sin']
#打印出前十個最常出現的詞語
getTopK(leesin_message_df, 10)

在這里插入圖片描述

#提取出被舉報的蘭博玩家的聊天記錄
rumble_message_df=offender_message_df[offender_message_df['champion_name']=='Rumble']
#打印出前十個最常出現的詞語
getTopK(rumble_message_df, 10)

在這里插入圖片描述
通過對上面兩個結果的比較我們可以發現,被舉報的盲僧玩家最常使用的詞語和整體結果非常類似而被舉報的蘭博玩家因為樣本量較少所以和整體結果還是有一定的差異性。但是這個結果是不是也從側面說明了被舉報的盲僧玩家對于所有被舉報的玩家來說是一群非常有代表性的樣本呢?

數據建模

在這一部分我的想法是既然被舉報的玩家使用的詞語有高度的相似性,那么能不能通過分類器來把被舉報玩家和普通玩家分類開呢?同時為了使本篇文章增添一點知識性我決定使用兩種分類模型:邏輯回歸分類器和樸素貝葉斯分類器,來比較兩種分類器的表現。

#把與分類有關的字段提取出來
classification_df=data.loc[:,['message','association_to_offender','chatlog_id']]
#刪除缺失值
classification_df.dropna(inplace=True)
#定義一個轉換函數
#把association_to_offender這一字段中的offender轉換為1其他類型轉換為0
#這樣就得到了二元分類的目標值
def transfer(x):if x == 'enemy':x=0elif x == 'ally':x=0else:x=1return x
#對association_to_offender這一字段進行轉換并把轉換后的值填入class字段
classification_df['class']=classification_df['association_to_offender'].apply(transfer)
#打印轉換后的數據框
classification_df.head()

在這里插入圖片描述
下面我們要對字符串數據進行預處理并且把每場游戲中class為0或class為1的字符串合并在一起.

#定義分詞器
tokenizer=RegexpTokenizer(r'\w+')
#對message字段中的字符串進行分詞
word_list=[tokenizer.tokenize(x) for x in classification_df['message']]
#對分詞后的單詞進行小寫轉換
for i in range(0,len(word_list)):word_list[i]=[word.lower() for word in word_list[i]]
#把轉換后的詞合并在一起
for i in range(0,len(word_list)):word_list[i] = ' '.join([str(word) for word in word_list[i]]) 
classification_df['message']=word_list
#對同一場對局的同一個class的字符串進行聚合
processed_classification_df=classification_df.groupby(['chatlog_id','class'],as_index=False).agg({'message': ' '.join})
#打印處理后的數據框
processed_classification_df.head()

在這里插入圖片描述
可以看到經過處理后的數據框中,同一場對局中非被舉報玩家的聊天記錄與被舉報玩家的聊天記錄已經分別合并在一起,也就是說現在數據集中50%為普通玩家的聊天記錄,50%為被舉報玩家的聊天記錄。

在使用分類模型之前,要對字符串進行轉換,對文本數據轉換的方法有很多,本文為了簡便使用的是sklearn中自帶的TF-IDF轉換器,并使用sklearn中的LogisticRegression和BernoulliNB來進行分類。

corpus=processed_classification_df['message']
vectorizer=TfidfVectorizer(lowercase=True,max_features=200,stop_words={'english'})
#轉換后的聊天記錄數據為X
X=vectorizer.fit_transform(corpus)
#目標值class為y
y=processed_classification_df['class']
#把數據集分割為訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
train_accuracy_list=[]
test_accuracy_list=[]
C_value_list=[]
#遍歷邏輯回歸分類不同超參數C的取值
for C in range(1,11):C_value=C/10C_value_list.append(C_value)clf = LogisticRegression(C=C_value).fit(X_train, y_train)y_train_predict = clf.predict(X_train)y_test_predict = clf.predict(X_test)train_accuracy = accuracy_score(y_train, y_train_predict)test_accuracy = accuracy_score(y_test, y_test_predict)train_accuracy_list.append(train_accuracy)test_accuracy_list.append(test_accuracy)
#繪制不同超參數C對應的訓練集和測試集準確率曲線
plt.plot(C_value_list,train_accuracy_list,label='Training Accuracy')
plt.plot(C_value_list,test_accuracy_list,label='Testing Accuracy')
plt.legend()
plt.xlabel('C value')
plt.ylabel('Accuracy')

在這里插入圖片描述
從這個結果可以看到,邏輯回歸分類器對于這個問題的表現還是很不錯的。測試集和訓練集的準確率都在90%左右且二者相差不大,說明沒有過擬合的問題,使用邏輯回歸來分辨被舉報者和普通玩家是完全可行的。那下面我們再來看看使用樸素貝葉斯分類器的效果。

clf = BernoulliNB().fit(X_train, y_train)
y_train_predict = clf.predict(X_train)
y_test_predict = clf.predict(X_test)
train_accuracy = accuracy_score(y_train, y_train_predict)
test_accuracy = accuracy_score(y_test, y_test_predict)
print('Training accuracy of Naive Bayes: {}'.format(train_accuracy))
print('Testing accuracy of Naive Bayes: {}'.format(test_accuracy))

在這里插入圖片描述
在這里插入圖片描述

可以看到使用樸素貝葉斯分類器時,準確率與邏輯回歸分類器相比稍差,其原因是樸素貝葉斯分類器的必要假設為特征之間是條件性獨立的關系,在本數據集中就表現為假設轉換后的TF-IDF數據框中每個單詞的出現與其他單詞無關,顯然該假設對于大多數的文本類型數據都是不成立的,但在大多數情況下樸素貝葉斯分類器依然可以有很好的表現。但對于一些比較復雜且特征之間存在強關聯性的分類問題,使用樸素貝葉斯分類器并不是一個很好的選擇。

寫在最后的話

本文為作者看到數據集后臨時起意,因此文中難免出現疏漏,希望各位讀者可以及時指出

若各位讀者對于本文內容有好的想法和建議可以與我交流

希望各位可以對本篇提出寶貴意見

轉載請注明出處

https://www.zydui.com/af9b5U28CDQ9VAF4C.html
>

相关文章:

  • pytorch中contiguous()
  • Solta沖刺美股:靠熱瑪吉9個月賺2億美元 林心如代言
  • pytorch中的contiguous()函數的淺淺解釋
  • 英雄聯盟數據分析專題(三)
  • 英雄聯盟無法啟動 因計算機中,發生了未知的dx錯誤,英雄聯盟無法啟動
  • for循環的3個表達式執行順序
  • D0712
  • C#中將字符轉換為鍵盤的鍵值keycode
  • 視頻去除原聲添加新的音樂時如何控制音量大小
  • 上古世紀服務器不穩定,《上古世紀》經典服火爆開服,玩家過多竟導致服務器崩潰!...
  • UK DN AS NN WG UX AA:這是一條加密推送!
  • 塔羅牌源碼|塔羅牌愛情占卜源碼
  • 深夜里,程序員最喜歡去的網站竟然是......
  • 2021/06/10| AMA:區塊鏈的內力與招式,RChain VS 其他鏈
  • 游戲自評——從電競化看LOL的設計/修改思路
  • lol最克制諾手的英雄_LOL最能克制諾手的5大英雄,誰敢來試試?
  • unity重定向_動畫重定向技術分析及其在Unity中的應用
  • 大數據之眼:無所不知的數字幽靈 - 電子書下載 -(百度網盤 高清版PDF格式)...
  • [App探索]JSBox中幽靈觸發器的實現原理探索
  • 通過labelme的json文件實現對圖片的批量裁剪
  • 同性社交軟件Blued整改:暫停注冊,對未成年人禁用
  • 數據安全建設中最難的是接口梳理,保護好接口就是保護好個人信息
  • 使用OpenCV進行實時車道檢測
  • OneAlert助力車行易提升事件響應效率,保障服務穩定性
  • 無人車行人識別---opencv
  • 車行無憂 v5.0.3 安卓版
  • 新人如何學配音?配音每日練習基本功學習?
  • winsock chapter6 - 地址家族和名字解析
  • 個人,傳承,家族?
  • VS的TFS(團隊資源管理器)