《Python數據分析與挖掘實戰》代碼糾錯4-1

最近在學習張良均老師的《Python數據分析與挖掘實戰》,發現部分代碼存在錯誤,特分享調試好的代碼,供學習參考。

代碼清單4-1 用拉格朗日法進行插補

書本代碼:

#拉格朗日插值代碼
import pandas as pd #導入數據分析庫Pandas
from scipy.interpolate import lagrange #導入拉格朗日插值函數

inputfile = '../data/catering_sale.xls' #銷量數據路徑
outputfile = '../tmp/sales.xls' #輸出數據路徑

data = pd.read_excel(inputfile) #讀入數據
data[u'銷量'][(data[u'銷量'] < 400) | (data[u'銷量'] > 5000)] = None #過濾異常值,將其變爲空值

#自定義列向量插值函數
#s爲列向量,n爲被插值的位置,k爲取前後的數據個數,默認爲5
def ployinterp_column(s, n, k=5):
  y = s[list(range(n-k, n)) + list(range(n+1, n+1+k))] #取數
  y = y[y.notnull()] #剔除空值
  return lagrange(y.index, list(y))(n) #插值並返回插值結果

#逐個元素判斷是否需要插值
for i in data.columns:
  for j in range(len(data)):
    if (data[i].isnull())[j]: #如果爲空即插值。
      data[i][j] = ployinterp_column(data[i], j)

data.to_excel(outputfile) #輸出結果,寫入文件

錯誤提示:

出錯的原因是1.出現警告"A value is trying to be set on a copy of a slice from a DataFrame"的原因是告訴我們在使用pandas中要極力避免利用chained indexing方式,即DataFrame[][]的形式去賦值,這裏解決方案是將data[u'銷量'][(data[u'銷量'] < 400) | (data[u'銷量'] > 5000)] = None改爲data.loc[(data[u'銷量'] < 400) | (data[u'銷量'] > 5000)] = None ;2.出現警告"Passing list-likes to .loc or [] with any missing label will raise KeyError in the future",這裏解決方案是將 y = s[list(range(n-k, n)) + list(range(n+1, n+1+k))]改爲y = s.reindex(list(range(n-k, n)) + list(range(n+1, n+1+k)));3.將data[i][j] = ployinterp_column(data[i], j)改爲data[i,j] = ployinterp_column(data[i], j)。

針對第報錯1,官方解釋爲:

當 Pandas 檢測到鏈式賦值(Chained Assignment)時會生成警告。爲了方便後續的解釋,先來解釋一些術語:

  • 賦值(Assignment) - 設置某些變量值的操作,例如 data = pd.read_csv('day-auctions.csv') ,有時會將這個操作稱之爲 設置(Set)
  • 訪問(Access) - 返回某些值的操作,具體參照下方的索引和鏈式索引示例。有時會將這個操作稱之爲 獲取(Get)
  • 索引(Indexing) - 任何引用數據子集的賦值或訪問方法,例如 data[1:5]
  • 鏈式索引(Chaining) - 連續使用多個索引操作,例如data[1:5][1:3]

 鏈式賦值是鏈式索引和賦值的組合。

警告是因爲將兩個索引操作鏈接在一起,直接使用了兩次方括號的鏈式索引比較容易理解。但如果使用其他訪問方法,例如 .bidderrate.loc[].iloc[].ix[],也會如此,這次的鏈式操作有:

  • data[data.bidder == 'parakeet']
  • ['bidderrate'] = 100

以上兩個鏈式操作一個接一個地獨立執行。第一次鏈式操作是爲了 Get,返回一個 DataFrame,其中包含所有 bidder 等於 'parakeet' 的行;第二次鏈式操作是爲了 Set,是在這個新返回的 DataFrame 上運行的,並沒有修改原始的 DataFrame。

這種情況對應的解決方案很簡單:使用 loc 將兩次鏈式操作組合成一步操作,從而確保 Pandas 進行 Set 的是原始 DataFrame。

修改後代碼:

#拉格朗日插值代碼
import pandas as pd #導入數據分析庫Pandas
from scipy.interpolate import lagrange #導入拉格朗日插值函數

inputfile = '../data/catering_sale.xls' #銷量數據路徑
outputfile = '../tmp/sales.xls' #輸出數據路徑

data = pd.read_excel(inputfile) #讀入數據
row_indexs = (data[u'銷量'] < 400) | (data[u'銷量'] > 5000)
data.loc[row_indexs,u'銷量'] = None #過濾異常值,將其變爲空值

#自定義列向量插值函數
#s爲列向量,n爲被插值的位置,k爲取前後的數據個數,默認爲5
def ployinterp_column(s, n, k=5):
  y = s.reindex(list(range(n-k, n)) + list(range(n+1, n+1+k)) )#取數
  y = y[y.notnull()] #剔除空值
  return lagrange(y.index, list(y))(n) #插值並返回插值結果

#逐個元素判斷是否需要插值
for i in data.columns:
  for j in range(len(data)):
    if (data[i].isnull())[j]: #如果爲空即插值。
      data[i,j] = ployinterp_column(data[i], j)

data.to_excel(outputfile) #輸出結果,寫入文件

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章