缺失值指資料集中某些變數的值有缺少的情況,缺失值也被稱為NA(not available)值。在pandas裡使用浮點值NaN(Not a Number)表示浮點數和非浮點數中的缺失值,用NaT表示時間序列中的缺失值,此外python內建的None值也會被當作是缺失值。需要注意的是,有些缺失值也會以其他形式出現,比如說用NULL,0或無窮大(inf)表示。
pip install d2l -i https://pypi.tuna.tsinghua.edu.cn/simple
import os
import pandas as pd
# 新增 測試資料
os.makedirs(os.path.join('.', 'data'), exist_ok=True)
data_file = os.path.join('.', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Test,Price\n')
f.write('NA,Pave,NA,127500\n')
f.write('2,D,A,106000\n')
f.write('4,NA,NA,178100\n')
f.write('NA,NA,B,14000\n')
# 讀取 csv 資料
data = pd.read_csv(data_file)
print("\nCSV data => \n", data)
print("-" * 60)
# 檢測缺失值
res_null = pd.isnull(data)
print("\nres_null => \n", res_null)
print("\nres_null.sum() => \n", res_null.sum())
# 透過位置索引iloc,將 data 分成 inputs、 outputs
inputs, outputs = data.iloc[:, 0:3], data.iloc[:, 3]
print("-" * 60)
刪除法
簡單,但是容易造成資料的大量丟失
1、刪除全為空值的行或列
data=data.dropna(axis=0,how='all') # 只刪除【全行】為缺失值的行資料
data=data.dropna(axis=1,how='all') # 只刪除【全列】為缺失值的列資料
2、刪除含有空值的行或列
data=data.dropna(axis=0,how='any') # 只要【行】中有缺失值的,刪除該【行】資料
data=data.dropna(axis=1,how='any') # 只要【列】中有缺失值的,刪除該列資料
axis : {0或'index',1或'columns'},預設0
確定是否刪除包含缺失值的行或列。
0或’index’:刪除包含缺失值的行。
1或“列”:刪除包含缺失值的列。
從0.23.0版開始不推薦使用:將元組或列表傳遞到多個軸上。只允許一個軸。
how : {'any','all'},預設為'any'
當我們有至少一個NA或全部NA時,確定是否從DataFrame中刪除行或列。
'any':如果存在任何NA值,則刪除該行或列。
'all':如果所有值均為NA,則刪除該行或列。
thresh : int,可選
需要許多非NA值。
subset :類陣列,可選
要考慮的其他軸上的標籤,例如,如果要刪除行,這些標籤將是要包括的列的列表。
inplace : bool,預設為False
如果為True,則對資料來源進行生效
示例
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(5, 3), index=list('abcde'), columns=['one', 'two', 'three']) # 隨機產生5行3列的資料
print(df)
df.iloc[1, :] = np.nan # 將指定資料定義為缺失
df.iloc[1:-1, 2] = np.nan
print("-" * 60)
print(df)
print("-" * 60)
print(df.dropna(axis=0))
import os
import pandas as pd
"""
刪除法:
簡單,但是容易造成資料的大量丟失
how = "any" 只要有缺失值就刪除
how = "all" 只刪除全行為缺失值的行
axis = 1 丟棄有缺失值的列(一般不會這麼做,這樣會刪掉一個特徵), 預設值為:0
"""
# 新增 測試資料
data_file = os.path.join('.', 'data', 'house_tiny.csv')
"""
輸入:
NumRooms Alley Test Price
0 NaN Pave NaN 127500.0
1 2.0 D NaN 106000.0
2 4.0 NaN NaN 178100.0
3 NaN NaN NaN NaN
輸出:
NumRooms Alley Test Price
0 NaN Pave NaN 127500.0
1 2.0 D NaN 106000.0
2 4.0 NaN NaN 178100.0
"""
print("-" * 60)
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Test,Price\n')
f.write('NA,Pave,NA,127500\n')
f.write('2,D,NA,106000\n')
f.write('4,NA,NA,178100\n')
f.write('NA,NA,NA,NA\n')
data = pd.read_csv(data_file)
print("\nCSV data => \n", data)
data.dropna(how="all", axis=0, inplace=True)
print("刪除之後的結果,只刪除全行為缺失值的行資料: \n", data)
"""
輸入:
NumRooms Alley Test Price
0 NaN Pave NaN 127500.0
1 2.0 D NaN 106000.0
2 4.0 NaN NaN 178100.0
3 NaN NaN NaN NaN
輸出:
NumRooms Alley Price
0 NaN Pave 127500.0
1 2.0 D 106000.0
2 4.0 NaN 178100.0
3 NaN NaN NaN
"""
print("-" * 60)
data.dropna(how="all", axis=1, inplace=True)
print("刪除之後的結果,只刪除全列為缺失值的列資料: \n", data)
"""
輸入:
NumRooms Alley Test Price
0 NaN Pave A 127500.0
1 2.0 D E 106000.0
2 4.0 NaN NaN 178100.0
3 NaN NaN B NaN
輸出:
NumRooms Alley Test Price
1 2.0 D E 106000.0
"""
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Test,Price\n')
f.write('NA,Pave,A,127500\n')
f.write('2,D,E,106000\n')
f.write('4,NA,NA,178100\n')
f.write('NA,NA,B,NA\n')
data = pd.read_csv(data_file)
print("\nCSV data => \n", data)
print("-" * 60)
data.dropna(how="any", axis=0, inplace=True)
print("刪除之後的結果,只要【行】中有缺失值的,刪除該【行】資料: \n", data)
"""
輸入:
NumRooms Alley Test Price
0 NaN Pave A 127500
1 2.0 D E 106000
2 4.0 NaN C 178100
3 NaN NaN B 14000
輸出:
Test Price
0 A 127500
1 E 106000
2 C 178100
3 B 14000
"""
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Test,Price\n')
f.write('NA,Pave,A,127500\n')
f.write('2,D,E,106000\n')
f.write('4,NA,C,178100\n')
f.write('NA,NA,B,14000\n')
data = pd.read_csv(data_file)
print("\nCSV data => \n", data)
print("-" * 60)
data.dropna(how="any", axis=1, inplace=True)
print("刪除之後的結果,只要【列】中有缺失值的,刪除該列資料: \n", data)
"""
輸入:
NumRooms Alley Test Price
0 NaN Pave A 127500
1 2.0 D E 106000
2 4.0 C NaN 178100
3 NaN NaN B 14000
輸出:
NumRooms Alley Test Price
0 NaN Pave A 127500
1 2.0 D E 106000
"""
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Test,Price\n')
f.write('NA,Pave,A,127500\n')
f.write('2,D,E,106000\n')
f.write('4,C,NA,178100\n')
f.write('NA,NA,B,14000\n')
data = pd.read_csv(data_file)
print("\nCSV data => \n", data)
print("-" * 60)
dt = data.dropna(subset=["Alley", "Test"])
print("刪除之後的結果,刪除 'Alley', 'Test': 有空值的行。\n", dt)
填充法
只要不影響資料分佈或者對結果影響不是很大的情況
數值型 ——可以使用均值、眾數、中位數來填充,也可以使用這一列的上下鄰居資料來填充
類別資料(非數值型) ——可以使用眾數來填充,也可以使用這一列的上下鄰居資料來填充
使用眾數來填充非數值型資料
fillna():使用指定的方法填充NA/NaN值。
返回值:DataFrame 缺少值的物件已填充。不改變原序列值。
引數解釋
- value :scalar(標量), dict, Series, 或DataFrame
用於填充孔的值(例如0),或者是dict / Series / DataFrame的值,
該值指定用於每個索引(對於Series)或列(對於DataFrame)使用哪個值。
不在dict / Series / DataFrame中的值將不被填充。該值不能是列表(list)。 - method : {‘backfill’,‘bfill’,‘pad’,‘ffill’,None},預設為None
填充重新索引的系列填充板/填充中的holes的方法:
將最後一個有效觀察向前傳播到下一個有效回填/填充:
使用下一個有效觀察來填充間隙。 - axis : {0或’index’,1或’columns’}
填充缺失值所沿的軸。
inplace : bool,預設為False
如果為True,則就地填充。
注意:這將修改此物件上的任何其他檢視
(例如,DataFrame中列的無副本切片)。 - limit : int,預設值None
如果指定了method,
則這是要向前/向後填充的連續NaN值的最大數量。
換句話說,如果存在連續的NaN數量大於此數量的缺口,
它將僅被部分填充。如果未指定method,
則這是將填寫NaN的整個軸上的最大條目數
如果不為None,則必須大於0。 - downcast : dict,預設為None
item-> dtype的字典,如果可能的話,將向下轉換,
或者是字串“infer”,
它將嘗試向下轉換為適當的相等型別
(例如,如果可能,則從float64到int64)。
import os
import pandas as pd
# 新增 測試資料
data_file = os.path.join('.', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Test,Price\n')
f.write('NA,Pave,NA,127500\n')
f.write('2,D,NA,106000\n')
f.write('4,NA,NA,178100\n')
f.write('NA,NA,NA,NA\n')
data = pd.read_csv(data_file)
print("\nCSV data => \n", data)
print("-" * 60)
# 處理缺失值,替換法 - 用當前列的平均值,填充 NaN
# 透過位置索引iloc,將 data 分成 inputs、 outputs
inputs, outputs = data.iloc[:, 0:4], data.iloc[:, 3]
a = inputs.fillna(inputs.mean())
print("\ninputs.fillna => \n", a)
b = inputs.fillna(inputs.mean(), limit=1)
print("\ninputs.fillna => \n", b)
插值法
最常用的插值函式就是interp1d,按照字面意思理解就是插值一個一維函式。其必不可少的輸入引數,就是將要被插值的函式的自變數和因變數,輸出為被插值後的函式
而所謂插值,要求只能在特定的兩個值之間插入,而對於超出定義域範圍的值,是無法插入的
在無宣告的情況下,插值方法預設是線性插值linear,如有其他需求,可變更kind引數來實現,可選插值方法如下:
- 樣條插值:其0、1、2、3階插值引數分別為zero、slinear、quadratic、cubic
- 返回單點:next和previous用於返回上一個或下一個值
- 最鄰近插值:nearest採取向下取整;nearest-up採用向上取整。
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate as si
x = np.arange(0, 10, 0.1)
y = np.sin(x)
plt.plot(x, y, 'o')
plt.show()
xnew = np.arange(0, 99)/10
f = si.interp1d(x, y)
ynew = f(xnew) #呼叫經由interp1d返回的函式
plt.plot(x, y, 'o', xnew, ynew, '-')
plt.show()
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate as si
x = np.arange(10)
y = np.sin(x)
plt.scatter(x[1:-1],y[1:-1])
xNew = np.arange(1,9,0.1)
ks = ['zero', 'slinear', 'quadratic', 'cubic']
cs = ['r', 'g', 'b', 'gray']
for i in range(4):
f = si.interp1d(x,y,kind=ks[i])
plt.plot(xNew, f(xNew), c=cs[i])
plt.show()
下圖中,紅、綠、藍、灰分別代表0到3次插值,可見,儘管只有10個點,但分段的二次函式已經描繪出了三角函式的形狀,其插值效果還是不錯的。
import numpy as np
from scipy.interpolate import interp1d
from scipy.interpolate import lagrange
# 插值法
# 線性插值 ——你和線性關係進行插值
# 多項式插值 ——擬合多項式進行插值
# 拉格朗日多項式插值、牛頓多項式插值
# 樣條插值 ——擬合曲線進行插值
# 對於線型關係,線型插值,表現良好,多項式插值,與樣條插值也表現良好
# 對於非線型關係,線型插值,表現不好,多項式插值,與樣條插值表現良好
# 推薦如果想要使用插值方式,使用拉格朗日插值和樣條插值
x = np.array([1, 2, 3, 4, 5, 8, 9])
y = np.array([3, 5, 7, 9, 11, 17, 19])
z = np.array([2, 8, 18, 32, 50 ,128, 162])
# 線型插值
linear_1 = interp1d(x=x, y=y, kind="linear")
linear_2 = interp1d(x=x, y=z, kind="linear")
linear_3 = interp1d(x=x, y=y, kind="cubic")
print("線性插值: \n", linear_1([6, 7])) # [13. 15.] 注意不是1是第一個索引
# print("線性插值: \n", linear_1([5, 6])) # [11. 13.]
print("線性插值: \n", linear_2([6, 7])) # [76. 102]
print("線性插值: \n", linear_3([6, 7])) # [76. 102]
# 拉格朗日插值
la_1 = lagrange(x=x, w=y)
la_2 = lagrange(x=x, w=y)
print("拉格朗日: \n", la_1) # [13, 15]
print("拉格朗日: \n", la_2) # [72, 98]
轉換為張量格式
import os
import pandas as pd
import numpy as np
import paddle
data_file = os.path.join('.', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Test,Price\n')
f.write('NA,Pave,NA,127500\n')
f.write('2,D,NA,106000\n')
f.write('4,NA,NA,178100\n')
f.write('NA,NA,NA,NA\n')
data = pd.read_csv(data_file)
# 對於非NaN型別的資料——先將非NaN型別的資料轉化為np.nan
data.replace("*", np.nan, inplace=True)
print("data: \n", data)
print(type(np.nan))
inputs, outputs = data.iloc[:, 0:4], data.iloc[:, 3]
print("-" * 60)
# 把離散的類別資訊轉化為 one-hot 編碼形式
inputs = pd.get_dummies(inputs, dummy_na=True)
print("\none-hot => \n", inputs)
# 轉換為張量格式
x, y = paddle.to_tensor(inputs.values), paddle.to_tensor(outputs.values)
print("\n to_tensor => \n", x, y)