為了更好地掌握數據科學必備庫Pandas的基本使用,本文通過精靈寶可夢的數據集實戰,我們一起過一遍Pandas的基本操作,文中的代碼都附有注釋,并給出了結果的配圖。
話不多說,我們開始吧!
- 導入pandas庫,并讀取csv文件
import pandas as pd
df=pd.read_csv('pokemon/Pokemon.csv')
- 查看DataFrame信息
df.info() # 數據類型,內存消耗等信息
df.describe() # 統計特征,均值方差等
- 查看DataFrame的前幾行以及后幾行
pd.head(n=5) # 可以添加參數n,表示顯示幾行
pd.tail()
- 顯示行列信息
df.index # 列索引
df.columns # 行索引
df.values # array對象
df.dtypes # 列元素屬性
- 刪除行列
df.drop(['#'],axis=1,inplace=True)
# 刪除‘#’列數據,在原DataFrame上改變
df.drop([1,2,3],axis=0)
# 刪除行索引為1、2、3的行,不在原DataFrame上改變
- 修改列名(兩種方法將‘Type 1’以及‘Type 2’中間的空格去掉)
df.rename(columns={'Type 1':'Type1','Type 2':'Type2'})
df.columns=df.columns.str.replace(' ','')
- 數據觀察
df['Defense'].mean() # 所有寶可夢Defense的均值
df['Attack'].argmax() # Attack最高的行索引
df['Sp.Atk'].idxmax() # Sp.Atk最高的行索引
df.sort_values('HP',ascending=False).head(3)
# HP最多的前三條數據
df['Type1'].unique() # Type1一共有哪些種類
df['Type1'].nunique() # Type1一共有幾種
df['Type2'].value_counts()
# Type2每種共有多少條
- 檢測空值
df.isnull().sum().sort_values(ascending=False)
# 將空值判斷進行匯總,按從高到低排序
- 空值填充
df['Type2'].fillna(value="Unknown",inplace=True)
# 將所有空缺值填為Unknown
df['Type2'].fillna(df['Type1'], inplace=True)
# 將所有Type2空缺值填為其對應Type1的值
- 刪除空值
df.dropna(how='any')
# 去除所有包含空值的行
- 去重
df.drop_duplicates(['Type1'],keep='first')
# 去除相同的Type1的數據,僅保留第一個
- 數據條件查詢
df[df['Name']=='Squirtle']
# 查看杰尼龜的數據
df[df['Type1'].isin(['Fire'])]
# 查看所有Type1為Fire的數據
df[(df['Generation']==1)&(df['Attack’]>=100)]
# 查看Generation為1并且攻擊力大于100的寶可夢
- 數據訪問方式(單行索引)
df.loc[3] # 訪問行索引為3的數據
df.iloc[3] # 訪問第4行數據,兩行代碼結果相同
- 數據訪問方式(區域索引,先行后列)
df.iloc[:5,:2] # 數據前5行前兩列,按位置索引
df.loc[10:15,['Generation','Attack','Sp.Atk']]
# 數據行標簽10-15,列標簽Generation,Attack和Sp.Atk,按標簽索引
df.loc[[10,11,12,13,14,15],['Generation','Attack','Sp.Atk']]
# 與上述寫法結果相同
df.loc[(df['Legendary']==True)|(df['Type1']=='Grass')]
# Legendary為真或者Type1為Grass的數據
- 參考資料:Pandas官方文檔
接下來我們主要涉及seaborn以及matplotlib兩個可視化庫。
上半篇我們主要使用matplotlib來進行柱狀圖、散點圖、餅圖折線圖等的繪制,下半篇主要使用seaborn來進行箱線圖、小提琴圖、分簇散點圖、熱力圖等的繪制。本文是下半篇,上半篇鏈接在這里。
箱線圖
箱線圖可以提供數據位置及其分散情況的關鍵信息,主要用于反映原始數據分布的特征,還可以進行多組數據分布特征的比較。
如上圖所示,箱線圖主要包含幾個關鍵的數據,上、下四方位數,中位數,上、下邊緣以及異常值。簡單來說,上四分位數表示全部數據中有四分之一的數據大于它,異常值表示遠離上或下四分位數。
我們來用箱線圖觀察一下寶可夢的各項屬性的分散情況。
df2=df.drop(['Generation','Total','Legendary'],axis=1)
sns.boxplot(data=df2)
plt.show()
可以看到每種屬性都有異常值,遠超于普通寶可夢,其中血量值的異常值數量最多。
接著我們來看不同的代目的各種屬性的分布特征,共用同一個Y軸,同時繪制四張子圖。
fig,axes=plt.subplots(1,4,sharey=True)
sns.boxplot(x="Generation",y="Attack",data=df,ax=axes[0])
sns.boxplot(x="Generation",y="Sp.Atk",data=df,ax=axes[1])
sns.boxplot(x="Generation",y="Defense",data=df,ax=axes[2])
sns.boxplot(x="Generation",y="Sp.Def",data=df,ax=axes[3])
fig.set_size_inches(20,7)
總體來看,五代目寶可夢的攻擊力水平要高于其他代目,二代目寶可夢的特殊攻擊水平要低于其他代目。
我們還可以用箱線圖來觀察不同類型的寶可夢對其防御數值的影響,結果顯而易見,鋼鐵類型的寶可夢擁有最為卓越的防御屬性。
plt.subplots(figsize=(20,5))
plt.title('Defence by Type 1')
sns.boxplot(x='Type1',y='Defense',data=df2)
plt.ylim(0,240) # 設置y軸的范圍
plt.show()
另外我們還可以在boxplot中添加參數hue,分門別類地進行箱線圖繪制,這里根據是否為神獸來做區分,顯然神獸的防御屬性遠超非神獸。
小提琴圖
小提琴圖結合了箱線圖與核密度估計圖的特點,它表征了在一個或多個分類變量情況下,連續變量數據的分布并進行了比較,它是一種觀察多個數據分布有效方法。
這里我們繪制不同類型的寶可夢的攻擊力值小提琴圖。
plt.title('Attack by Type1')
sns.violinplot(x="Type1", y ="Attack",data=df2)
plt.ylim(0,200)
plt.show()
小提琴圖中寬度較厚的部分表示具有較高密度點的區域,而較薄的部分則表示低密度點的區域。我們可以清楚地看到有一部分電系寶可夢的攻擊力在60左右,小提琴圖有明顯的膨脹部分;而巖石系的寶可夢的攻擊力分布較為平均,小提琴圖呈長窄形狀。
我們對不同代目的寶可夢繪制了總屬性值的小提琴圖,并且將是否為神獸區分開來。
plt.title('Strongest Generation')
sns.violinplot(x="Generation",y="Total",data=df,hue="Legendary",split=True)
plt.show()
根據小提琴圖我們似乎可以得出一代目的神獸實力最為強勁,三代目的非神獸實力則更優。
熱力圖
這里采用熱力圖來可視化數據各列之間的相關性。可以看到特殊攻擊、攻擊和特殊防御的數值與是否為神獸的相關性較高,而代目與其他數據的相關性較低。
df3=df.drop(['Total'],axis=1)
sns.heatmap(df3.corr(),annot=True)
plt.show()
分簇散點圖
分簇散點圖可以理解為數據點不重疊的分類散點圖,swarmplot函數類似于stripplot函數,但該函數可以對點進行一些調整,使得數據點不重疊。
swarmplot()可以自己實現對數據分類的展現,也可以作為箱線圖、小提琴圖的一種補充,用來顯示所有結果以及基本分布情況。
首先通過melt將寶可夢的各項數據匯到同一列中,即把窄寬的數據拉伸為長瘦型,將寶可夢的各項數值按照類型以分簇散點圖的形式展現出來。
df5=pd.melt(df2, id_vars=["Name", "Type1", "Type2"], var_name="Stat")
sns.swarmplot(x="Stat", y="value", data=df5, hue="Type1",dodge=True)
plt.legend(bbox_to_anchor=(1, 1), loc=2, borderaxespad=0.)
plt.show()
參考資料
- Visualizing Pokémon Stats with Seaborn
- Seaborn官方文檔