佛爺帶你用Python視覺化分析 ”絕地求生1800萬遊戲資料“,穩穩吃雞!
本文內容和程式碼實現基本轉自By datayx。筆者在此之上,做了內容完善和程式碼完善。
98k消音,瞭解一下~
經常玩吃雞遊戲,我們現在來分析一下過去一年 1800萬條遊戲資料,看看有什麼套路幫我們吃到雞。
1. 資料集描述
做資料分析或者機器學習的我們,對於資料是很敏感的。本文資料來自 Kaggle,分遊戲場次資料和玩家擊殺資料兩部分,各有10G左右。
視訊遊戲是資料提取的一個豐富領域。諸如複雜的魔獸世界補血以及俠盜獵車手自動駕駛汽車等知名例子告訴我們,視訊遊戲比我們真正想象的更接近現實。資料科學家可以深入瞭解玩家在假想和虛擬場景中所面臨的邏輯和決策。
在這個Kaggle資料集中,我提供了來自流行遊戲PlayerUnknown’s Battlegrounds的超過720,000場競技比賽。資料來自pubg.op.gg,一個遊戲追蹤器網站。我打算讓這個資料集純粹是探索性的,但使用者可以自由建立他們認為合適的預測模型。
PUBG是第一個/第三人稱射擊遊戲royale風格的遊戲,與超過90名玩家在一個大島上相遇,在這個大島上,團隊和玩家一直戰鬥直到死亡。玩家從飛機上空投到島上,在那裡他們將清除城鎮和建築物的武器,彈藥,裝甲和急救裝置。然後玩家將決定與最後一個站立的終極目標戰鬥或隱藏。一個藍色區域將在遊戲中出現幾分鐘,通過對站在藍色區域內的任何人造成傷害並阻止任何處於安全區域內的人員,將玩家拉近和靠近在一起。
該資料集提供了兩個部分:聚合和死亡。
在死亡資料中,這些檔案記錄了在720k比賽中發生的每一次死亡。也就是說,每一行都記錄了一名玩家在比賽中死亡的事件。
在聚合資料中,總結每個比賽的元資訊和玩家統計資料(由pubg提供)。它包括各種綜合統計資料,例如玩家擊殺,傷害,步行距離等,以及比賽本身的元資料,如佇列大小,fpp / tpp,日期等。未壓縮的資料分成5塊,每塊大約2GB。
解釋位置資料:X,Y座標全部在遊戲內座標中,需要線性縮放以在方形erangel和miramar地圖上繪製。最小,最大座標分別為0,800,000。
2. 開場跳哪裡,可以避免落地成盒?
不少玩家吐槽遊戲剛開始幾分鐘就落地成盒,遊戲體驗不好。其實跳傘選一個安全的地方降落很重要。首先來看開場4分鐘內落地成盒的地點。
看到上圖是否恍然大悟,深紅色的地方就是最危險的,海島地圖上分別是軍事基地、學校、P城、G港、防空洞,而沙漠地圖最明顯,扎堆兩個地方:聖馬丁城和皮卡多城。
那跳哪裡是安全且資源又多的呢? 海島地圖上Y城和P港就是常常被人群遺忘的地方,可以放心搜。其實也不難發現,海岸沿線以及橋頭位置都是安全地,跳傘跳到這,落地成盒到概率會大大降低。
程式碼如下:
import pandas as pd
from scipy.ndimage.filters import gaussian_filter
import matplotlib.cm as cm
from matplotlib.colors import Normalize
from scipy.misc.pilutil import imread
import numpy as np
import matplotlib.pyplot as plt
# 先把玩家被擊殺的資料匯入
death_0 = pd.read_csv('F:\pubg-match-deaths\deaths\kill_match_stats_final_0.csv')
death_1 = pd.read_csv('F:\pubg-match-deaths\deaths\kill_match_stats_final_1.csv', nrows=5000000)
death = death_0.merge(death_1, how='outer')
print(death.shape)
# (18426348, 12)
# 篩選落地成盒的玩家(選取開局4分鐘之內死亡的玩家)
in_240_seconds_erg = death.loc[(death['map'] == 'ERANGEL') & (death['time'] < 240), :].dropna()
in_240_seconds_mrm = death.loc[(death['map'] == 'MIRAMAR') & (death['time'] < 240), :].dropna()
data_erg = in_240_seconds_erg[['victim_position_x', 'victim_position_y']].values
data_mrm = in_240_seconds_mrm[['victim_position_x', 'victim_position_y']].values
data_erg = data_erg * 4096 / 800000
data_mrm = data_mrm * 1000 / 800000
def heatmap(x, y, s, bins=100):
heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
heatmap = gaussian_filter(heatmap, sigma=s)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
return heatmap.T, extent
bg = imread('F:\pubg-match-deaths\erangel.jpg')
hmap, extent = heatmap(data_erg[:, 0], data_erg[:, 1], 4.5)
alphas = np.clip(Normalize(0, hmap.max(), clip=True)(hmap) * 4.5, 0.0, 1.)
colors = Normalize(0, hmap.max(), clip=True)(hmap)
colors = cm.Reds(colors)
colors[..., -1] = alphas
fig, ax = plt.subplots(figsize=(24, 24))
ax.set_xlim(0, 4096)
ax.set_ylim(0, 4096)
ax.imshow(bg)
ax.imshow(colors, extent=extent, origin='lower', cmap=cm.Reds, alpha=0.9)
plt.gca().invert_yaxis()
plt.savefig('out1.png', dpi=100)
bg = imread('F:\pubg-match-deaths\miramar.jpg')
hmap, extent = heatmap(data_mrm[:, 0], data_mrm[:, 1], 4.5)
alphas = np.clip(Normalize(0, hmap.max(), clip=True)(hmap) * 4.5, 0.0, 1.)
colors = Normalize(0, hmap.max(), clip=True)(hmap)
colors = cm.Reds(colors)
colors[..., -1] = alphas
fig, ax = plt.subplots(figsize=(24, 24))
ax.set_xlim(0, 1000)
ax.set_ylim(0, 1000)
ax.imshow(bg)
ax.imshow(colors, extent=extent, origin='lower', cmap=cm.Reds, alpha=0.9)
plt.gca().invert_yaxis()
plt.savefig('out2.png', dpi=100)
3. 哪裡才是最佳吃雞地點?
沒有落地成盒那誰都有機會吃雞。裝備可以很快撿完,玩得溜的大神當然是四處搜人舔包,而大多數普通玩家會選擇往毒圈內跑,然後躲起來。瞎跑會有很大概率被狙擊。現在關心的是哪裡是決賽圈的概率最大?我們直接跑向決賽圈,也就是吃雞率較高的地方,當個伏地魔,人來了先下手狙人
以上兩圖分別是海島和沙漠地圖最終吃雞地點的分部分圖。可以看出,決賽圈的位置分佈很廣,第一次縮圈後的每個位置都有可能是決賽圈,而概率比較大的幾個地方,跟跳傘扎堆的地方基本一致,而且是地圖的中心處。撿完裝備往中心跑倒是個不錯的選擇。
另外聯想到一個問題,決賽圈和扎堆跳傘的位置重合,那是不是說明吃雞的大神在跳傘落地後都不會移動太遠,而只是在落地附近打埋伏?
程式碼如下:
last_seconds_erg = death.loc[(death['map'] == 'ERANGEL') & (death['killer_placement'] == 1), :].dropna()
last_seconds_mrm = death.loc[(death['map'] == 'MIRAMAR') & (death['killer_placement'] == 1), :].dropna()
data_erg = last_seconds_erg[['victim_position_x', 'victim_position_y']].values
data_mrm = last_seconds_mrm[['victim_position_x', 'victim_position_y']].values
data_erg = data_erg * 4096 / 800000
data_mrm = data_mrm * 1000 / 800000
bg = imread('F:\pubg-match-deaths\erangel.jpg')
hmap, extent = heatmap(data_erg[:, 0], data_erg[:, 1], 4.5)
alphas = np.clip(Normalize(0, hmap.max(), clip=True)(hmap) * 4.5, 0.0, 1.)
colors = Normalize(0, hmap.max(), clip=True)(hmap)
colors = cm.Reds(colors)
colors[..., -1] = alphas
fig, ax = plt.subplots(figsize=(24, 24))
ax.set_xlim(0, 4096)
ax.set_ylim(0, 4096)
ax.imshow(bg)
ax.imshow(colors, extent=extent, origin='lower', cmap=cm.Reds, alpha=0.9)
plt.gca().invert_yaxis()
plt.savefig('out3.png', dpi=100)
last_seconds_mrm = death.loc[(death['map'] == 'MIRAMAR') & (death['killer_placement'] == 1), :].dropna()
data_erg = last_seconds_erg[['victim_position_x', 'victim_position_y']].values
data_mrm = last_seconds_mrm[['victim_position_x', 'victim_position_y']].values
data_erg = data_erg * 4096 / 800000
data_mrm = data_mrm * 1000 / 800000
bg = imread('F:\pubg-match-deaths\miramar.jpg')
hmap, extent = heatmap(data_mrm[:, 0], data_mrm[:, 1], 4.5)
alphas = np.clip(Normalize(0, hmap.max(), clip=True)(hmap) * 4.5, 0.0, 1.)
colors = Normalize(0, hmap.max(), clip=True)(hmap)
colors = cm.Reds(colors)
colors[..., -1] = alphas
fig, ax = plt.subplots(figsize=(24, 24))
ax.set_xlim(0, 1000);
ax.set_ylim(0, 1000)
ax.imshow(bg)
ax.imshow(colors, extent=extent, origin='lower', cmap=cm.Reds, alpha=0.9)
plt.gca().invert_yaxis()
plt.savefig('out4.png', dpi=100)
4. 選擇帶什麼武器容易吃雞?
相信不少玩家最關心這個。來看圖:
上圖是所有吃到雞的玩家所佩帶的武器分佈,自動步槍M416 是他們的最愛。也可以發現,他們帶自動步槍比狙擊步槍要多很多。狙擊槍裡面,98k赫赫有名也是名副其實。
既然吃到雞的玩家帶的步槍多,那是否說明他們優先選擇近戰,而不是遠距離狙擊??
程式碼如下:
last_seconds_erg = death.loc[(death['map'] == 'ERANGEL')&(death['killer_placement']==1), :].dropna()
last_seconds_erg['killed_by'].value_counts()[1:10].sort_values().plot.barh(figsize=(10,5))
plt.yticks(fontsize=12)
plt.savefig('out5.png', dpi=100)
5. 遠近戰與吃雞概率的關係
下圖是篩選出吃到雞的玩家,這是他們擊殺人頭的距離分佈
不難發現500米內的近戰佔了大多數,吃到雞的玩家更偏愛近戰,對敵人反應快。而長距離狙擊的大神只在少數,比如5000米以上,這些都是熟練操作8倍鏡了。
程式碼如下:
last_seconds_erg = death.loc[(death['killer_placement'] == 1), :].dropna()
distance = np.sqrt(((last_seconds_erg['killer_position_x'] - last_seconds_erg['victim_position_x']) / 100) ** 2 + (
(last_seconds_erg['killer_position_y'] - last_seconds_erg['victim_position_y']) / 100) ** 2)
distance = distance.apply(lambda x: int(x))
labels = [0, 10, 30, 50, 100, 200, 500, 800, 1000, 1500, 2000, 3000, 5000, 10000, 20000]
distan_cut = pd.cut(distance, bins=labels)
distan_cut.value_counts().plot.bar(figsize=(10, 8))
plt.savefig('out6.png', dpi=100)
6. 擊殺數與吃雞概率的關係
玩過農藥的的童鞋都會知道,收人頭收得越多,技能加成越大,傷害越來越大,無人能擋時就是勝利在望。而在吃雞裡面,能活到最後一個就是王者,所以很明顯擊殺人頭越多,吃到雞的概率並不一定大。那一場遊戲裡面,擊殺多少個算厲害來呢??
我們篩選比賽中所有排名第一的玩家,看看他們是擊殺數分佈:
看上圖是不是挺意外,單場比賽擊殺2個以內的佔多數,吃到雞的人也不例外,他們並不追求人頭,猥瑣發育也很重要.
小白玩家也不必擔心一場遊戲裡沒人頭,擊殺一兩個機器人也算是收穫不小來。
程式碼如下:
match_stats = pd.read_csv('F:/pubg-match-deaths/aggregate/agg_match_stats_0.csv')
winer = match_stats.loc[(match_stats['team_placement'] == 1), :].dropna()
labels = [0, 2, 5, 8, 11, 15, 20, 30, 40, 50]
winer['kill'] = pd.cut(winer['player_kills'], bins=labels)
winer['assist'] = pd.cut(winer['player_assists'], bins=labels)
winer['kill'].value_counts().plot.bar(figsize=(10, 10))
plt.savefig('out7.png', dpi=100)