數據分析
內容多且雜,我按照自己理解的邏輯,寫了三個思維導圖,就在每一部分之後
一、基礎概念及環境
1. 數據分析概念
- 數據分析是Python數據科學的基礎,也是機器學習課程的基礎
- 數據分析: 大量的數據進行分析,幫助人們作出判斷,以便採取適當行動。
2. anaconda
2.3 安裝
- 搜索“anaconda”鏡像源
- 下載到Linux主機。可以使用wget命令下載。
- chomd +x 給下載的sh文件可執行權限,然後執行
- 一路輸入yes
- 關閉終端,再打開一個新終端即生效
2.2 基本操作
- 創建環境:
conda create -n 取的名字 python=3
確定後,輸入Y安裝
- 激活環境:
source activate 環境名
- 停用環境:
source deactivate
- 安裝模塊:
conda install 模塊名
二、matplotlib
1. 簡介
- 將數據進行可視化 ,更直觀
- 使數據更客觀 ,更具說服力
- matplotlib: 最流行的Python底層繪圖庫,注意做數據可視化圖表 ,名字取材於MATLAB,也是模仿其構建的。
2. 基本要點
- axis: 指x或y這種座標軸。
- 座標: 圖上的每一個點就是一個座標。
- 安裝:(pip3 install matplotlib安裝會報錯。請使用以下命令。)
sudo apt-get install python3-matplotlib
3. 使用方法
- 以折線圖爲例
3.1 最簡單形式
- 導入模塊
- x,y都要是可迭代對象。並且長度相同。
- 將x、y傳入plot
- 展示圖形(會蹦出一個框,當然,遠程看不了)
# coding=utf-8
from matplotlib import pyplot as plt
x = [0, 2, 4, 6]
y = [20, 15, 14, 13]
plt.plot(x, y) # 傳入x,y通過plot繪製折線圖
plt.show() # 在執行時,展示圖形
- 如果想保存圖片,控制刻度怎麼辦?
3.2 升級形式
- 我們想保存圖片,就需要創建一個圖形實例。figsize接收一個元組,分別是寬和高。dpi決定清晰度,意思是每英寸點個數。在繪圖之後,保存即可。
- 控制刻度。
# coding=utf-8
from matplotlib import pyplot as plt
# 創建一個圖形實例,後續對其進行設置操作
fig = plt.figure(figsize=(20,10), dpi=80) # (寬,高),每英寸點個數
x = range(2, 26, 2)
y = [20, 15, 14, 13, 8, 16, 14, 14, 13, 11, 10, 15]
# 繪圖
plt.plot(x, y)
# 設置x軸刻度
# xtick_labels = [0.5*i for i in range(4, 49, 1) # range不接受小數步長
plt.xticks(range(2, 25, 1)) # 設置區間爲2~25,步長爲1
# 設置y軸刻度
plt.yticks(range(min(y), max(y)+1, 3))
# 保存
plt.savefig("./pic/t1.png") # 可以保存爲svg矢量圖格式
# 展示
# plt.show()
- 刻度想要使用字符串怎麼辦?字符串擠在一起怎麼辦?怎麼使用中文?
3.3 刻度使用字符串
- 刻度傳入一個參數,只能使用數字。傳入兩個參數,可以使用字符串,要一一對應。
- 刻度擠在一起,可以選擇用rotation參數旋轉。
- 中文:在終端用fc-list可以查看Linux中支持的字體。在用fc-list :lang=zh可以看含有的中文字體
- 改變字體有兩種方式。方式2更可取。字體的地址,最好用絕對字體。
# coding=utf-8
from matplotlib import pyplot as plt
import random
from matplotlib import font_manager
# 設置字體,方式1
# font = {"family" : "MicroSoft YaHei",
# "weight" : "bold",
# "size" : "larger"}
# matplotlib.rc("font", **font)
# 設置字體,方式2(推薦)
my_font = font_manager.FontProperties(fname="/home/pi/Font/simsun.ttc")
# 創建一個圖形實例,後續對其進行設置操作
fig = plt.figure(figsize=(30,25), dpi=120) # (寬,高),每英寸點個數
x = range(1, 121)
# 描繪一個增長的股票
y = [int(random.randint(15, 90)*0.03*i) for i in range(1, 121)]
# 繪圖
plt.plot(x, y)
# 調整x軸刻度
_x = list(x) # 可以直接用x。轉換爲列表是爲了方便控制步長。
_xtick_labels = ["10點{}分".format(i) for i in range(60)]
_xtick_labels += ["14點{}分".format(i) for i in range(60)]
# 一個參數時,只能傳數字。要傳入字符串,需要讓兩個參數一一對應
plt.xticks(_x[::5], _xtick_labels[::5], rotation=315, fontproperties=my_font) # rotation決定旋轉的度數
# 設置y軸刻度
plt.yticks(range(min(y), max(y)+1, 7))
# 保存
plt.savefig("./pic/t2.png") # 可以保存爲svg矢量圖格式
# 展示
# plt.show()
3.4 添加描述信息
- 繪製網格:
plt.grid()
grid可以接受參數。
alpha=0.4 ==>設置透明度爲0.4(完全透明爲0,完全不透明爲1,缺省爲1)
- 添加描述信息:
plt.xlabel("時間", fontproperties=my_font)
plt.ylabel("股價 (單位¥)", fontproperties=my_font)
plt.title("兩個時間段的股價變化", fontproperties=my_font)
3.5 同圖表繪製多折線
- 繪圖兩次即可
# 繪圖
plt.plot(x, y1)
plt.plot(x, y2)
- 給曲線添加圖例(區別曲線) 用label參數,還要添加plt.legend()
# 繪圖
plt.plot(x, y1, label="星期三")
plt.plot(x, y2, label="星期五")
plt.legend(prop=my_font) # 注意是prop,其它地方用字體都是fontproperties參數
圖例默認在最合適的位置。要改變位置使用loc參數,可以傳入字符串,也可以傳入數字0~10
best | upper right | upper left | lower left | lower right | right |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 |
center left | center right | lower center | upper center | center | |
6 | 7 | 8 | 9 | 10 |
- 繪圖:顏色參數color,傳入顏色單詞或16進制值
- 繪圖:線型參數linestyle,傳入字符串(網格也有這個參數哦)
- | – | -. | : | ‘’ |
---|---|---|---|---|
實線 | 虛線 | 點劃線 | 點虛線 | 留空 |
- 線條粗細:linewidth=5
- 線條透明度:alpha=0.5
4. 應用場景
- 折線圖: 變化。顯示數據變化趨勢。
- 直方圖: 統計(繪製連續性的數據)展示一組或多組數據分佈情況
- 條形圖: 統計(繪製離散型的數據)能夠一眼看出各個數據的大小,比較數據之間的差別。頻率統計。
- 散點圖: 分佈規律(判斷變量之間是否存在數量關聯趨勢,展示離羣點)
- 其它問題:
plt.hist()直方圖==>錯位?錯位是因爲不能被整除。
可以用條形圖,設置width(width默認0.8)即可。
5. 更多
百度Echarts
plotly可視化工具中的github。同時兼容matplotlib和pandas
seaborn比matplotlib簡單,但沒有交互效果
6. 思維導圖
三、numpy
- Python中的一個科學計算 基礎庫。重在數值計算 。
1. 創建數組&數據類型
- 創建數組
import numpy as np
# 以下都是一維數組
np.array([5])
np.array(range(1, 12, 2))
np.arange(1, 12, 2)
- 數據類型
# 指定創建的數組的數據類型
t1 = np.array([1, 0], dtype=np.bool)
t1 = np.array([1, 0], dtype="?")
# 查看t1數組裏的數據類型
t1.dtype
# 修改數據類型
t2 = t1.astype("i1")
# 修改小數位數
t3 = np.array([0.233333, 0.666666])
t4 = np.round(t3, 2) # [0.23, 0.67],和Python中round方法類似
類型 | 類型代碼 | 說明 |
---|---|---|
int8 | i1 | 有符號8位(1字節)整形 |
uint8 | u1 | 無符號8位(1字節)整形 |
int16/32/64 | i2/i3/i4 | 以此類推 |
float16 | f2 | 半精度浮點數 |
float32 | f4或f | 標準單精度浮點數。兼容C的float |
float64 | f8或d | 標準的雙精度浮點數。兼容C的double和Python的float |
float128 | f16或g | 擴展精度浮點數 |
complex256 | c32 | 複數 |
bool | ? | 布爾值 |
2. 數組的形狀
- 一維數組
array([0, 1, 2, 3, 4, 5])
- 二維數組
array([
[1, 2, 3],
[4, 5, 6]
])
- 三維數組
array([
[
[1, 2, 3],
[4, 5, 6]
],
[6, 5, 4],
[3, 2, 1]
])
- 讓t1接收上面那個一維數組,t2接收2維,t3接收3維。
- 形狀 shape可以知道數組的形狀。
t1.shape ==> (5,)
t2.shape ==> (2,3)
t3.shape ==> (2,3,3)
- 改變形狀有返回值,不會改變數組本身。
t4 = np.arange(12)
t4.reshape((3, 4)) ==>array([
[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]
])
- 展開(變1維) 有返回值,不會改變數組本身。
t4.flatten()
3. 數組計算
3.1 數組計算(與數字)
- 做加減乘除法會讓每一個值都加減乘除上這個數(廣播機制)
- 除0
nan,全稱not a number,表示不是一個數字,是一種特殊的數據類型。
inf, 全稱infinity表示無窮。
任何非零數除以零=無窮。0除以0不是一個數字。
3.2 數組計算(與數組)
- 加減乘除都是對應位置進行加減乘除(形狀完全相同時)
- 加減乘除都是對應位置進行加減乘除(某一維度形狀相同時)
會發現同一維度進行計算
- 廣播原則: 如果兩個數組的後緣維度(即從末尾開始算的維度) 的軸長度相符,或其中一方長度是1 ,則認爲他們是廣播兼容的。廣播會在缺失和(或)長度爲1的維度上進行。
shape爲(3, 3, 2)能與(3, 2)進行計算。也能和(3, 1)進行計算。
二維的很好理解。三維的,把第一個維度看作區塊,就好理解了。可以參考下面軸圖。
4. 軸
- 在numpy中可以理解爲方向。一維數組只有一個0軸。二維數組有0軸和1軸。以此類推。(我畫的多維維數組軸和一般畫法不一致,因爲我的理解是最前面的維度最高。所以axis=0應該是最高維度軸。)
- 有了軸的概念後,計算會更加方便。比如計算平均值,必須指定是哪個方向上的平均值。
5. numpy從文件讀取數據
np.loadtxt(frame, dtype=np.float, delimiter=None, skiprows=0, usecols=None, unpack=False)
參數 | 含義 |
---|---|
frame | 文件、字符串或產生器的路徑。可以是.gz或bz2壓縮文件 |
dtype | 數據類型,可選。默認np.float |
delimiter | 分隔字符串,默認是任何空格 |
skiprows | 跳過前X行 |
usecols | 讀取指定列 |
unpack | 表示轉置。True:讀入屬性將分別寫入不同數組變量。False:只寫入一個數組變量,默認False。 |
DEMO
- 準備四個CSV文件。
CSV中的數據都是以逗號分隔開的。
- 看一個最基礎示例:
import numpy as np
file_PATH_1 = "./data_1.csv"
datas_1 = np.loadtxt(file_PATH_1, dtype="int", delimiter=",", skiprows=1)
print(datas_1)
- 看一下轉置的效果:
import numpy as np
file_PATH_1 = "./data_1.csv"
datas_1 = np.loadtxt(file_PATH_1, dtype="int", delimiter=",", skiprows=1)
datas_1_u = np.loadtxt(file_PATH_1, dtype="int", delimiter=",", skiprows=1, unpack=True)
print(datas_1)
print(">>>>>>下面是轉置後的結果<<<<<<")
print(datas_1_u)
- 轉置有非常多的方法:
t2 = t1.transpose()
t2 = t1.T
t2 = t2.swapaxes(1, 0) # 把0軸和1軸交換
6. numpy索引和切片
6.1 索引與切片的一般形式
- 取行的方法: (注意第三個特殊用法)
# 取datas第1行
print("-" * 50)
print(datas_1[0])
# 取第1行-->第6行
print("-" * 50)
print(datas_1[0:6])
# 取1、5、7行
print("-" * 50)
print(datas_1[[0, 4, 6]]) # 這是個特殊用法
- 通用方法: datas_1[axis0, axis1] axis0和axis1都可以進行切片等操作
- 取列、行和列及某處值:
# 取第1列
print("-" * 50)
print(datas_1[:, 0])
# 取前5行,1、3列
print("-" * 50)
print(datas_1[:5, [0, 2]])
- 取一個特定值:
返回一個numpy.int值
# 取3行,4列
print("-" * 50)
print(datas_1[2, 3])
print("它的類型是%s" % type(datas_1[2, 3])) # numpy.int型
- 取多個特定點:
行和列一一對應,如果是二維的,返回一個一維數組
# 取(1,2)和(3,4)點
print("-" * 50)
print(datas_1[[0,2], [1,3]])
6.2 numpy索引進階
- 修改某一處的值使用賦值語句: (可以讓一堆數據等於同一個值)
# 修改(2, 3)的值
print("-" * 50)
print(datas_1[:3]) # 打印一下原始數組前三行
print()
datas_1[:3][1,2] = 1314 # 使用賦值語句修改
print(datas_1[:3]) # 再次打印,查看結果
# 修改(1, 1)、(1, 3)和後兩行
print("-" * 50)
print(datas_1[:3]) # 打印一下原始數組前三行
print()
datas_1[:3][[0,0],[0,2]] = 520 # 使用賦值語句修改
datas_1[:3][1:] = 520 # 使用賦值語句修改
print(datas_1[:3]) # 再次打印,查看結果
- numpy中布爾索引:
(怎樣把滿足條件的值替換?)
在交互式解釋器中試驗,發現是布爾值。
把布爾值列表套進去,發現是爲True的部分
- numpy中三目運算符:
(然後同時執行if和else?)
np.where()用法同Excel中if。直接返回,不會修改原數組。
- clip剪切: (將大於某數的,全替換爲此數,將小於某數的,全部替換爲此數。保持中間的數不變。)
- 修改值爲nan:
nan屬於非整形,如果原數組中都是整數,那麼需要先將數據類型轉化爲float(使用t1.astype(float)方法),纔可以使用賦值語句,使其等於np.nan。
7. 數組拼接與拆分
7.1 數組拼接
- np.vstack((,))豎直拼接。
- np.hstack((,))水平拼接。
7.2 數組分割
- np.vsplit()豎直方向的均等分割。
- np.hsplit()水平方向的均等分割。
7.3 交換行列
- 交換行:
原理類似於:
a, b = 1, 0 # 交換a, b的值
b, a = a, b
DEMO:將多個文件中數據組合
- np.zeros((形狀)).astype(int) 生成一塊數組,值爲0
- np.ones((形狀 )).astype(int) 生成一塊數組,值爲1
- 形狀可以理解爲行列
- 需求: 有兩個文件的數據,需要添加一列,來自於第一個文件的,該數爲0,。來自第二個文件的,該數爲1。
import numpy as np
# 構造來自第一個文件數據
file_PATH_1 = "./data_1.csv"
datas_1 = np.loadtxt(file_PATH_1, dtype="int", delimiter=",", skiprows=0)
add_v_1 = np.zeros((datas_1.shape[0],1)) # 生成一列0的數組
final_data_1 = np.hstack((add_v_1, datas_1)).astype("int") # 不轉會是科學計算法
# 構造來自第二個文件數據
file_PATH_2 = "./data_2.csv"
datas_2 = np.loadtxt(file_PATH_2, dtype="int", delimiter=",", skiprows=0)
add_v_2 = np.ones((datas_2.shape[0],1)) # 生成一列0的數組
final_data_2 = np.hstack((add_v_2, datas_2)).astype("int") # 不轉會是科學計算法
# >>>>>>>>>>組合起來<<<<<<<<<<
final_data = np.vstack((final_data_1, final_data_2))
print(final_data)
8. 更多
8.1 正方形數組、某條軸計算
- 創建一個對象爲1的正方形數組(方陣):
np.eye(3)
8.2 隨機值
- numpy中有許多隨機數方法
方法 | 功能 |
---|---|
.rand(d0, d1, …dn) | 創建d0~dn維度的均勻分佈的隨機數數組(0~1之間,浮點數) |
.randn(d0, d1, …dn) | 創建d0~dn維度的標準正態分佈隨機數數組(0~1之間,浮點數,平均數0,標準差1) |
.randint(low,high,(shape)) | 給定上下限範圍選取隨機數。形狀shape |
.uniform(low,high,(size)) | 和上面的那個一樣,不過產生的是浮點數 |
.normal(loc, scale, (size)) | 從指定正態分佈中隨機抽取樣本,分佈中心是loc(概率分佈均值),標準差是scale,形狀是size |
.seed(s) | 隨機數種子,s是給定的種子值(放一個數)。(因爲計算機是僞隨機,所以在使用同一個種子後,再執行以上的任一隨機方法可以得到相同的隨機數) |
seed和randint是最常用的。
8.3 copy和view
- a = b 完全不復制,a和b指向同一個內存空間。是淺拷貝。
- a = b[:] 視圖 的操作,一種切片,會創建新的對象a,但是a的數據完全由b保管 ,兩者數據變化一致。也是一種淺拷貝。
- a = b.copy() 深拷貝。
8.4 nan和inf
- nan表示不是一個數字
- 出現nan的兩種情況:
- 讀取數據有缺失時。
- 當做了一個不合適的計算時。
- ifn表示無窮。除0,python中會直接報錯,數組會顯示inf。
- nan和inf都是float類型的。
8.4.1 nan
- 兩個nan不相等
利用這一個特性。可以產生特殊用途
t1 != t1
所有地方都是False。而nan因爲不相等,所以它所在的位置會變爲True。
np.count_nonzero(t1)
可以統計出t1中非0的個數。False會被識別爲零,所以np.count_nonzero(t1 != t1)
可以計算出nan的個數。
t1 != t1
有一個代替的方法:np.isnan(t1)
- nan和任何值進行計算都爲nan
可以
t1[isnan(t1)] = 0
來進行一個賦值的操作,不然很多計算無法進行
但是能用0嗎?求和是無影響,求積應該用1,求平均值就應該先算出其它不爲nan的數據的平均值賦予它。也可以替換爲中值,或乾脆刪了那一行。
8.4.2 常用統計方法:
8.4.2.1 以max和min來說明軸和全體的計算方法:
t1.max()
t1.min()
- 行(列)方向上最大(最小):
返回一個數組
t1.max(axis=0) # 0軸上最大值
t1.min(axis=1) # 1軸上最小值
- 獲取最大值(最小值的位置):
t1.argmax(axis=0)
t1.argmin(axis=1)
np.argmax(t1, axis=0) # 效果同上,寫法不同
8.4.2.2 更多統計方法
t1.sum()
求和t1.mean()
求均值np.median( t1 )
求中值np.ptp(t)
極差t.std()
標準差
8.4.3 替換nan
- 怎樣把nan替換爲平均數之類的數呢?
- 準備一個數組t1
import numpy as np
def del_nan(t1):
for i in range(t1.shape[1]): # 遍歷每一列
temp_col = t1[:,i] # 當前的一列
nan_num = np.count_nonzero(np.isnan(temp_col))
if nan_num != 0: # 不爲0,說明當前這一列中有nan
temp_unan_col = temp_col[temp_col==temp_col] # 當前一列不爲nan的array
temp_col[np.isnan(temp_col)] = temp_unan_col.mean() # 選中nan的位置,給其賦值
return t1
if __name__ == "__main__":
# 準備一個供操作的數組
t1 = np.arange(12).reshape((3, 4)).astype("float")
t1[1, 2:] = np.nan
print(t1)
t1 = del_nan(t1)
print(t1)
- 有幾個要點:
- 用shape來獲取多少列。然後搭配range遍歷。
- temp_col = t1[:,i] 取出當前的一列
- 當t爲一維數組時,t[t==t]會返回不爲nan的array。
8.5 numpy 與 matplotlib合作
- 準備一個numpy文件處理數據
- 準備一個matplotlib文件接收數據並畫圖
- 畫出來的圖是這樣的:
我們會發現有離羣點,怎麼剔除離羣點呢?必定是數據方面的問題
通過觀察,我們剔除y>10萬的,x>55萬的
這裏我們利用布爾索引改變原始數組(不能直接改x或y)
9. 思維導圖
三、pandas
- pandas除了處理數值外(基於numpy),還能夠幫助我們處理其他類型的數據
- 常用數據類型:
- Series一維,帶標籤數組
- DataFrame二維,Series容器
1. Series
1.1 Series基礎
- Series一維,帶標籤數組。那麼,什麼是標籤呢?
import pandas as pd
t1 = pd.Series([1, 5, 7])
- 標籤就是索引。索引可以指定,必須和數組一樣長。(以下兩種方式都可)
t2 = pd.Series([1, 5, 7], index=["鉛筆", "布", "鐮刀"])
t3 = pd.Series({"鉛筆":1, "布":5, "鐮刀":7})
- 類字典的這種也可以重新賦予索引。
- 而且變成浮點了
a = {"鉛筆":1, "布":5, "鐮刀":7}
t3 = pd.Series(a, index = {"電線杆", "布", "旗幟"})
行爲類似:小張有鉛筆,布和鐮刀;你向其要了電線杆,布和旗幟;小張就告訴你,他只有布(這個布有5種顏色:5可以理解爲屬性,描述),其它就是nan。
- 修改dtype(和numpy一樣操作)
- 切片和索引
像列表和字典那樣操作。對於像字典的類型,也可以通過位置來取。
- 取不連續點和布爾索引(同numpy)
- 取出所有鍵、值(返回的結果是可迭代的)
字符串類型就會顯示爲object。t2是int64類型的,由此可見t2的dtype是由value決定的。
t2.index是pandas.indexes.base.Index
類型。t2.values是數組類型。
- 可見,Series是由“標籤”+“數組”組成的,再品味一下,帶標籤的一維數組是什麼意思。
- ndarray的很多方法可以運用與Series類型,比如argmax,clip等
- Series的where方法和ndarray不同:
讀取外部數據
方法 | 讀取 |
---|---|
read_csv | 讀取csv |
read_cliboard | 讀取剪切板 |
read_excel | 讀取Excel |
read_html | 讀取html |
read_json | 讀取json |
read_sql | 從數據庫 |
a = pd.read_csv("./文件名.csv")
pd.read_sql(sql語句, connection鏈接)
TODO:這是鏈接MongoDB的用法
from pymongo import MongoClient
import pandas as pd
client = MongoClient()
collection = client["douban"]["tv1"]
data = list(collection.find())
a = pd.read_sql(sql語句, connection鏈接)
3. DataFrame
- Series一維,帶標籤數組
- Dataframe二維,Series容器
豎着的這一列稱爲index (行索引),橫着的這一列稱爲columns (列索引)。
- 只看index列和A列,會發現這是一個Series。只看columns行和1列…這就是爲什麼DataFrame被稱爲Series容器
- 傳入字典: 會發現鍵是列索引,很像我之前提到的升維(值裏面的列表,就是一個Series)
- 傳入列表: (如果有缺失的,會呈現nan)
基礎屬性查詢
- 查看索引、值
會發現,值是數組類型的
- 查看形狀&列數據類型
- 查看數據維度
整體情況查詢
- head顯示頭部幾行(默認5),tail顯示末尾幾行(默認5)
- info相關信息概覽:
由DataFrame創建。行索引3個,從0~2。列索引,總共四個:A,3個非空值,列類型int64,內存佔用136bytes。
- describe快速綜合統計結果(只會統計含數字的):
計數、平均、標準差、最小值、分位點、最大值
DEMO:按照統計次數進行排序
- 準備一個csv文件,Count_AnimalName就是統計次數,現在要從大到小排序
- 先看一下情況:
可以發現,Row_Labels少了三個數據
- 進行排序:
# 按某一列進行排序。False表降序,不填默認升序。
t1.sort_values(by="排序的字段", ascending=False)
- 最終代碼:
import pandas as pd
datas = pd.read_csv("./dogNames2.csv")
# print(datas.head())
# print(datas.info())
del_datas = datas.sort_values(by="Count_AnimalName", ascending=False)
print(del_datas.head())
切片
- 取前10行,第一列
del_datas[:10]["Row_Labels"]
pandas中,方括號取數字,表示對行進行操作。去字段名,表示對字段進行操作。
loc
- t1.loc通過標籤索引行數據
和數組切片方式類似。
下面這種方法比較特殊(因爲是鍵表示索引,所以比較特殊,右邊也會被選中)
t1.loc通過位置獲取行數據(這種方法就跟數組切片索引完全一致)
- 這裏居然可以直接賦值nan(不用先轉化爲float類型),並且可以進行統計(排除nan之後的其它數據進行統計)
布爾索引
- 一個條件時
del_datas = datas[datas["Count_AnimalName"]>777]
- 多個條件時,用括號包起條件,再用&連接
del_datas = datas[(datas["Count_AnimalName"]>777)&(datas["Count_AnimalName"]<1024)]
&表示且;|表示或
pandas之字符串方法
- to_list()可以將單字段轉變爲一個大列表
方法 | 說明 |
---|---|
cat | 元素級的字符串連接操作,可指定分隔符 |
contains | 返回表示各字符串是否含有指定模式的布爾型數組 |
count | 模式出現的次數 |
endswith/startswith | 相當於對每個元素執行x.endswith(pattern)或x.startswith(pattern) |
findall | 計算各字符串的模式列表 |
get | 獲取各元素的第i個字符 |
join | 根據指定的分隔符,將Series中各元素的字符串連接起來 |
len | 計算各字符串的長度 |
lower/upper | 轉換大小寫。相當於對各個元素執行x.lower()或x.upper() |
match | 根據指定的正則表達式對各個元素執行re.match |
pad | 在字符串的左、右或左右添加空白符 |
center | 相當於pad(side=“both”) |
repeat | 重複值。s.str.repeat(3)相當於對各個字符串執行x*3 |
replace | 用指定字符串替換找到的模式 |
slice | 對Series中各個字符串進行子串截取 |
split | 根據分隔符或正則表達式對字符串進行拆分 |
strip/rstrip/lstrip | 取出空白符,包括換行符。相當於對各個元素執行x.strip()/x.rstrip()/x.lstrip() |
- 比如選出字符串長大於3的:
del_datas = datas[datas["Row_Labels"].str.len()>3]
缺失數據處理
- pd.isnull(t1)返回一個布爾df。是nan的地方就爲True。還有一個notnull方法,正好相反。
- 使用布爾嵌套
刪除數據
- dropna刪除含nan的。dropna(axis=指定軸, how=“刪除方式”, inplace=False)
- axis=0表示刪除行。
- 刪除方式默認爲any,表示只要有nan就把整行/列刪了。也可以指定爲all,表示該行/列只有全部爲nan,纔會刪除。
- inplace是很多方法都有的,表示是否進行原地替換,默認爲False。下面兩種方法效果是一致的:
填充數據
- fillna,填充nan
可以用t1.mean()來獲取平均值。再填充進去。
- 有時候,數據中的0是表示數據缺失的,這時候,先將其變爲nan,再進行操作。
t1[t1==0]=np.nan
pandas常用統計方法
獲取個數
# 取一維
len(set(df["需要獲取個數的索引"].tolist()))
# 相當於下面,unique是唯一的意思
df["需要獲取個數的索引"].unique()
# 取二維
temp = df["需要獲取個數的索引"].str.split(",").tolist() # 變成一個列表
alist = [i for j in temp for i in j] # 展開就變爲一維了,再用len(set(list就可以了
字符串離散化的案例
- 這裏有一堆電影類型,要統計
- 原理參考下面
- 代碼:
import pandas as pd
import numpy as np
file_path = "./IMDB-Movie-Data.csv"
df = pd.read_csv(file_path)
genre = df["Genre"]
# 1. 構建不重複的電影類型列表
genre_list_in_list = genre.str.split(",").tolist() # 嵌套列表
genre_list = list(set([i for j in genre_list_in_list for i in j]))
# 2. 構建全爲0的數組
zeros_df = pd.DataFrame(np.zeros((df.shape[0], len(genre_list))), columns=genre_list)
# 3. 給每個電影出現的類型,賦值1
for i in range(df.shape[0]):
# zeros_df.loc[0, ["恐怖片", "喜劇片"]] = 1
zeros_df.loc[i, genre_list_in_list[i]] = 1
# print(zeros_df)
# 4. 統計每個分類的個數
count_df = zeros_df.sum(axis=0)
# print(count_df)
# 5.排序
# count_df是一個Series
rank_s = count_df.sort_values()
# print(rank_s)
# 6.製圖
x = rank_s.index
y = rank_s.values.astype(int)
bar.bar(x, y)
from matplotlib import pyplot as plt
from matplotlib import font_manager
from random import randint
def bar(x, y):
# 數據
x = x
y = y
# 設置圖形實例
plt.figure(figsize=(20,10), dpi=80)
# 設置字體
my_font = font_manager.FontProperties(fname="/home/pi/Font/simsun.ttc")
# 繪圖
plt.barh(x, y, height=0.3)
# 刻度
max_y = max(y)
min_y = min(y)
plt.yticks(x, fontproperties=my_font, rotation=330)
plt.xticks(range(min_y, max_y, 50), fontproperties=my_font)
# 保存
plt.savefig("./s1.png")
數據合併join
- 以df1的行爲準,合併列
- merge方法就是mysql裏的關聯表的操作:
- 按“a”列左連接
- 按“a”列取並集(外連接),合併行列
- 按"a"列取交集,合併行(其實是內連接,省略了how="inner"參數)
- 以左表的"f",和右表的"a"
數據分組聚合
- 這裏有一張表“星巴克在各地門店數表”,想知道在中國各個城市的門店數量
分組聚合方法
import pandas as pd
file_path = "starbucks_store_worldwide.csv"
df =pd.read_csv(file_path)
# print(df.info())
# 1.調用分組方法
groups = df.groupby(by="Country")
- 它爲DataFrameGroupBy對象
- 該對象可以進行遍歷、調用聚合方法
- 查看美國所有星巴克門店詳細信息表
df[df["Country"] == "US"]
- 統計每個國家有多少家
print(groups["City"].count())
- 查看中國有多少家(上面那個相當於一個Series,對其直接取索引即可)
country_count = groups["Brand"].count() # Brand是隨便選的字段
print(country_count["CN"]) # 打印中國店鋪數量
DEMO:找出中國每個省份的店鋪數量
china_data = df[df["Country"] == "CN"] # 利用布爾索引,找出中國的數據
groups = china_data.groupby(by="State/Province").count()["Brand"] # 按所在地分組,隨便取一個字段來統計(這裏選了Brand)
print(groups)
- 聚合方法:
函數名 | 說明 |
---|---|
count | 統計分組中非NA的數量 |
sum | 非NA的和 |
mean | 非NA的平均值 |
median | 非NA的算術中位數 |
std/var | 無偏(分母爲n-1)標準差/方差 |
min/max | 求非NA的最大/最小 |
多條件分組
groups = df.groupby(by= ["Country", "State/Province"]).count()
前面的兩列作爲索引
- 假如要取出Brand列,有兩種方法:
# 方式1。因爲Brand裏沒有Country字段,所以需要使用特殊形式
groups = df["Brand"].groupby(by= [df["Country"], df["State/Province"]]).count()
# 方式2
groups = df.groupby(by= [df["Country"], df["State/Province"]]).count()["Brand"]
# 方式3,就是方式2換了順序
groups = df.groupby(by= [df["Country"], df["State/Province"]])["Brand"].count()
- 一處小語法細節: 對比一下兩者區別(提示:類型)
索引
- 把上面的索引方法打印一下:
print(groups.index)
# 只打印部分數據
MultiIndex(levels=[['AD', 'AE', 'AR'], ['0', '1', '10']],
labels=[[0, 1, 1]],
names=['Country', 'State/Province'])
levels包含索引(包括索引Country和索引State/Province),labels包含索引的值,names包含索引字段名
index可以用來賦值
- 重新設置index
df.index = ["a", "b"]
- 從df裏取兩行(如果某行不存在,那麼會那行會返回nan)
df.reindex(["a", "不存在的行"])
- 把當前某一列作爲索引 (重點)
df.set_index("Countre", drop=False) # drop參數默認爲True,表示作爲索引後是否要保留該列
- 查看一下其索引返回的結果:
- 返回index的唯一值:df.index.unique()
- index是一個可迭代對象
Series複合索引
- 分組後如何取值: (先取列索引,行索引一級一級取)
- 交換列索引:
- 分組後取值的方法2:
- 然後從字段中取某一部分的思路:
如果某個信息藏在某個字段中。比如姓名字段中,我們只需要前面的姓氏。可以先讀出所有姓名的字段,再通過新建一個姓氏字段:
df["新建的姓氏字段"] = pd.DataFrame(取得的姓氏)
最後再依據此字段,分組即可
時間序列
時間戳DatetimeIndex
pd.data_range(start=None, end=None, periods=None, freq=“D”)
- 參數說明:
start、end決定時間序列的始終
periods表示生成個數
freq表示頻率,D表示以天爲間隔
一般是start和end在一起使用,或者start和periods一起使用,不會同時使用
縮寫 | 單詞 | 含義 |
---|---|---|
D | Day | 日曆日 |
B | BusinessDay | 工作日 |
H | Hour | 小時 |
T或min | Minute | 分 |
S | Second | 秒 |
L或ms | Milli | 毫秒(千分之一秒) |
U | Micro | 微秒(百萬分之一秒) |
M | MonthEnd | 每月最後一個日曆日 |
BM | BusinessMonthEnd | 每月最後一個工作日 |
MS | MonthBegin | 每月第一個日曆日 |
BMS | BusinessMonthBegin | 每月第一個工作日 |
- 類型是Index類,一般也用做生成時傳入Index
- 把時間戳轉化成DF時間序列
df[“時間所在字段”] = pd.to_datetime(df[“timeStamo”], format="")
當時間所在字段裏的時間,不符合時間序列格式規範時,用format把其格式傳入(格式化)
20191001符合規範,2019/10/01符合規範,2019-10-01符合規範…
時間格式化
- 重採樣: 將時間序列從一個頻率轉化爲了一個頻率進行處理的過程 , 將高頻率轉化爲低頻率爲降採樣 ,反之爲升採樣 。
t.resample(“M”).mean()按月取平均數
# 把時間戳轉化爲DF時間類型
df["timeStamp"] = pd.to_datetime(df["timeStamp"])
df.set_index("timeStamp", inplace=True)
# 統計不同月份的數據
count_by_month = df.resample("M").count()
# 上述會得到一個DF,再取數據沒有缺失的那一列即可
- 如果繪圖時,出現了時分秒,又不需要:
-x = [i.strftime("%Y%m%d") for i in x_original_list]
時間段PeriodIndex
periods = pd.PeriodIndex(year=df["year"], month=df["month"], day=df["day"], hour=df["hour"], freq="H")
# 給時間段採樣
data = df.set_index(periods).resample("10D").mean()
- DEMO:測算PM2.5隨小時變化
import pandas as pd
file_path = "./BeijingPM20100101_20151231.csv"
df = pd.read_csv(file_path)
periods = pd.PeriodIndex(year=df["year"], month=df["month"], day=df["day"], hour=df["hour"], freq="H")
# 增加一列,把分開的時間字符串,組合
df["datatime"] = period
# 把datatime設置爲索引
df.set_index("datatime", inplace=True)
# 處理缺失數據,刪除缺失數據。返回一個Series,Index是時間,值是PM2.5
data = df["PM_US Post"].dropna()
- DEMO:測算PM2.5隨10天變化
import pandas as pd
file_path = "./BeijingPM20100101_20151231.csv"
df = pd.read_csv(file_path)
periods = pd.PeriodIndex(year=df["year"], month=df["month"], day=df["day"], hour=df["hour"], freq="H")
# 增加一列,把分開的時間字符串,組合
df["datatime"] = period
# 把datatime設置爲索引
df.set_index("datatime", inplace=True)
# 進行降採樣
df = df.resample("10D").mean()
# 返回一個Series,Index是時間,值是PM2.5
data = df["PM_US Post"]