Numpy 系列(十一)- genfromtxt函數

定義輸入

genfromtxt的惟一強制參數是數據的源。它能夠是字符串,字符串列表或生成器。若是提供了單個字符串,則假定它是本地或遠程文件或具備read方法的打開的類文件對象的名稱,例如文件或StringIO.StringIO對象。若是提供了字符串列表或返回字符串的生成器,則每一個字符串在文件中被視爲一行。當傳遞遠程文件的URL時,文件將自動下載到當前目錄並打開。 python

識別的文件類型是文本文件和歸檔。目前,該函數識別gzipbz2bzip2)歸檔。歸檔的類型從文件的擴展名肯定:若是文件名以'.gz'結尾,則須要一個gzip歸檔;若是以'bz2'結尾,則假設存在一個bzip2檔案。數組

將行拆分爲列

delimiter 參數

一旦文件被定義並打開閱讀,genfromtxt將每一個非空行拆分爲一個字符串序列。剛剛跳過空行或註釋行。delimiter關鍵字用於定義拆分應如何進行。函數

一般,單個字符標記列之間的間隔。例如,逗號分隔文件(CSV)使用逗號(,)或分號(;)做爲分隔符:spa

import numpy as np
from io import BytesIO

data = b"1, 2, 3\n4, 5, 6"
np.genfromtxt(BytesIO(data), delimiter=",")
Out[334]: 
array([[1., 2., 3.],
       [4., 5., 6.]])

另外一個常見的分隔符是"\t",表格字符。可是,咱們不限於單個字符,任何字符串都會作。默認狀況下,genfromtxt假定delimiter=None,表示該行沿白色空格(包括製表符)分割,而且連續的空格被視爲單個白色空格。code

或者,咱們可能處理固定寬度的文件,其中列被定義爲給定數量的字符。在這種狀況下,咱們須要將delimiter設置爲單個整數(若是全部列具備相同的大小)或整數序列(若是列能夠具備不一樣的大小):orm

data = b"1, 2, 3\n4, 5, 6"
np.genfromtxt(BytesIO(data), delimiter=",")
Out[334]: 
array([[1., 2., 3.],
       [4., 5., 6.]])
data = b"  1  2  3\n  4  5 67\n890123  4"
np.genfromtxt(BytesIO(data), delimiter=3)
Out[336]: 
array([[  1.,   2.,   3.],
       [  4.,   5.,  67.],
       [890., 123.,   4.]])
data = B"123456789\n   4  7 9\n   4567 9"
np.genfromtxt(BytesIO(data), delimiter=(4, 3, 2))
Out[338]: 
array([[1234.,  567.,   89.],
       [   4.,    7.,    9.],
       [   4.,  567.,    9.]])

autostrip參數

默認狀況下,當一行被分解爲一系列字符串時,各個條目不會被刪除前導或尾隨的空格。經過將可選參數autostrip設置爲True的值,能夠覆蓋此行爲:對象

data = b"1, abc , 2\n 3, xxx, 4"
np.genfromtxt(BytesIO(data), delimiter=",", dtype="|S5")
Out[340]: 
array([[b'1', b' abc ', b' 2'],
       [b'3', b' xxx', b' 4']], dtype='|S5')
np.genfromtxt(BytesIO(data), delimiter=",", dtype="|S5", autostrip=True)
Out[341]: 
array([[b'1', b'abc', b'2'],
       [b'3', b'xxx', b'4']], dtype='|S5')

omments參數blog

可選參數comments用於定義標記註釋開始的字符串。默認狀況下,genfromtxt假設爲comments='#'註釋標記能夠出如今該行的任何地方。忽略註釋標記後的任何字符:索引

data = b"""#
# Skip me !
# Skip me too !
1, 2
3, 4
5, 6 #This is the third line of the data
7, 8
# And here comes the last line
9, 0
"""
np.genfromtxt(BytesIO(data), comments="#", delimiter=",")
Out[345]: 
array([[1., 2.],
       [3., 4.],
       [5., 6.],
       [7., 8.],
       [9., 0.]])

注意ip

這種行爲有一個顯着的例外:若是可選參數names=True,則將首先檢查第一條註釋的行的名稱。

忽略某些行或某些列

skip_header 和 skip_footer 參數

文件中頭的存在可能阻礙數據處理。在這種狀況下,咱們須要使用skip_header可選參數。此參數的值必須是對應於在執行任何其餘操做以前在文件開頭處跳過的行數的整數。相似地,咱們可使用skip_footer屬性並賦予n的值來跳過文件的最後n行:

>>> data = "\n".join(str(i) for i in range(10))
>>> np.genfromtxt(BytesIO(data),)
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])
>>> np.genfromtxt(BytesIO(data),
...              skip_header=3, skip_footer=5)
array([ 3.,  4.])

默認狀況下,skip_header=0skip_footer=0,表示不跳過任何行。

usecols 參數

在某些狀況下,咱們對數據的全部列不感興趣,但只對其中的幾個列感興趣。咱們可使用usecols參數選擇要導入哪些列。此參數接受單個整數或對應於要導入的列的索引的整數序列。記住,按照慣例,第一列的索引爲0。負整數的行爲與常規Python負指數相同。

例如,若是咱們只想導入第一列和最後一列,可使用usecols =(0, -1)

>>> data = "1 2 3\n4 5 6"
>>> np.genfromtxt(BytesIO(data), usecols=(0, -1))
array([[ 1.,  3.],
      [ 4.,  6.]])

若是列具備名稱,咱們還能夠經過將其名稱做爲字符串序列或逗號分隔字符串的形式,將其名稱指定給usecols參數來選擇要導入的列:

>>> data = "1 2 3\n4 5 6"
>>> np.genfromtxt(BytesIO(data),
...              names="a, b, c", usecols=("a", "c"))
array([(1.0, 3.0), (4.0, 6.0)],
     dtype=[('a', '<f8'), ('c', '<f8')])
>>> np.genfromtxt(BytesIO(data),
...              names="a, b, c", usecols=("a, c"))
   array([(1.0, 3.0), (4.0, 6.0)],
         dtype=[('a', '<f8'), ('c', '<f8')])

    選擇數據類型

控制如何將從文件中讀取的字符串序列轉換爲其餘類型的主要方法是設置dtype參數。此參數的可接受值爲:

  • 單個類型,例如dtype=float除非已使用names參數將名稱與每一個列相關聯(參見下文),不然輸出將爲具備給定dtype的2D。請注意,dtype=floatgenfromtxt的默認值。

  • 類型序列,例如dtype =(int, float, float)

  • 逗號分隔的字符串,例如dtype="i4,f8,|S3"

  • 具備兩個鍵'names''formats'的字典。

  • 元組的序列(名稱, 類型),例如dtype = [('A', t4 > int), ('B', float)]

  • 現有的numpy.dtype對象。

  • 特殊值None在這種狀況下,列的類型將從數據自己肯定(見下文)。

在全部狀況下,但第一個,輸出將是具備結構化dtype的1D數組。此dtype具備與序列中的項目同樣多的字段。字段名稱使用names關鍵字定義。

dtype=None時,每一個列的類型從其數據中迭代肯定。咱們首先檢查字符串是否能夠轉換爲布爾值(即,若是字符串在小寫字符串中匹配truefalse);那麼它是否能夠轉換爲整數,而後到一個float,而後到一個複雜,最終到一個字符串。能夠經過修改StringConverter類的默認映射器來更改此行爲。

爲方便起見,提供了選項dtype=None可是,它明顯慢於明確設置dtype。

 設置 names

names 參數

處理表格數據時的一種天然方法是爲每一個列分配一個名稱。第一種可能性是使用顯式結構化dtype,如前所述:

>>> data = BytesIO("1 2 3\n 4 5 6")
>>> np.genfromtxt(data, dtype=[(_, int) for _ in "abc"])
array([(1, 2, 3), (4, 5, 6)],
     dtype=[('a', '<i8'), ('b', '<i8'), ('c', '<i8')])

另外一個更簡單的可能性是使用names關鍵字與一系列字符串或逗號分隔的字符串:

>>> data = BytesIO("1 2 3\n 4 5 6")
>>> np.genfromtxt(data, names="A, B, C")
array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)],
     dtype=[('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

在上面的示例中,咱們使用了默認狀況下,dtype=float的事實。經過給出一系列名稱,咱們將輸出強制爲結構化的dtype。

咱們有時可能須要從數據自己定義列名稱。在這種狀況下,咱們必須使用值Truenames關鍵字。而後將從第一行(在skip_header以後)讀取名稱,即便行被註釋掉:

>>> data = BytesIO("So it goes\n#a b c\n1 2 3\n 4 5 6")
>>> np.genfromtxt(data, skip_header=1, names=True)
array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)],
     dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])

 

names的默認值爲None若是咱們爲關鍵字賦予任何其餘值,新名稱將覆蓋咱們可能已使用dtype定義的字段名稱:

>>> data = BytesIO("1 2 3\n 4 5 6")
>>> ndtype=[('a',int), ('b', float), ('c', int)]
>>> names = ["A", "B", "C"]
>>> np.genfromtxt(data, names=names, dtype=ndtype)
array([(1, 2.0, 3), (4, 5.0, 6)],
     dtype=[('A', '<i8'), ('B', '<f8'), ('C', '<i8')])

defaultfmt 參數 

If names=None but a structured dtype is expected, names are defined with the standard NumPy default of "f%i", yielding names like f0f1 and so forth:

>>> data = BytesIO("1 2 3\n 4 5 6")
>>> np.genfromtxt(data, dtype=(int, float, int))
array([(1, 2.0, 3), (4, 5.0, 6)],
     dtype=[('f0', '<i8'), ('f1', '<f8'), ('f2', '<i8')])

一樣,若是咱們沒有給出足夠的名稱來匹配dtype的長度,那麼將使用此默認模板定義缺乏的名稱:

>>> data = BytesIO("1 2 3\n 4 5 6")
>>> np.genfromtxt(data, dtype=(int, float, int), names="a")
array([(1, 2.0, 3), (4, 5.0, 6)],
     dtype=[('a', '<i8'), ('f0', '<f8'), ('f1', '<i8')])

咱們可使用defaultfmt參數覆蓋此默認值,它採用任何格式字符串:

>>> data = BytesIO("1 2 3\n 4 5 6")
>>> np.genfromtxt(data, dtype=(int, float, int), defaultfmt="var_%02i")
array([(1, 2.0, 3), (4, 5.0, 6)],
     dtype=[('var_00', '<i8'), ('var_01', '<f8'), ('var_02', '<i8')])

注意

咱們須要記住,defaultfmt僅在預期某些名稱但未定義時使用。

Validating names

具備結構化dtype的NumPy數組也能夠視爲recarray,其中能夠像訪問屬性同樣訪問字段。所以,咱們可能須要確保字段名稱不包含任何空格或無效字符,或者不符合標準屬性的名稱(例如sizeshape),這將會混淆解釋器。genfromtxt接受三個可選參數,對名稱提供更精細的控制:

  • deletechars

  • 提供一個字符串,組合必須從名稱中刪除的全部字符。默認狀況下,無效字符爲〜!@#$%^&amp; *() - = +〜\ |]} [{';: /?.& &lt;

  • excludelist

  • 提供要排除的名稱列表,例如returnfileprint ...若是輸入名稱之一是此列表的一部分,將在其後面添加下劃線字符('_')。

  • case_sensitive

是否名稱應區分大小寫(case_sensitive=True),轉換爲大寫(case_sensitive=Falsecase_sensitive='upper')或小寫(case_sensitive='lower')。

轉換調整

converters 參數

一般,定義一個dtype足以定義如何轉換字符串序列。然而,有時可能須要一些額外的控制。例如,咱們可能要確保格式YYYY/MM/DD的日期被轉換爲datetime對象,或者像xx%已正確轉換爲0到1之間的浮點值。在這種狀況下,咱們應該使用converters參數定義轉換函數。

此參數的值一般是具備列索引或列名做爲鍵和轉換函數做爲值的字典。這些轉換函數能夠是實際函數或lambda函數。在任何狀況下,他們應該只接受一個字符串做爲輸入,只輸出所需類型的一個元素。

在如下示例中,第二列從表示百分比的字符串轉換爲0到1之間的浮點數:

>>> convertfunc = lambda x: float(x.strip("%"))/100.
>>> data = "1, 2.3%, 45.\n6, 78.9%, 0"
>>> names = ("i", "p", "n")
>>> # General case .....
>>> np.genfromtxt(BytesIO(data), delimiter=",", names=names)
array([(1.0, nan, 45.0), (6.0, nan, 0.0)],
     dtype=[('i', '<f8'), ('p', '<f8'), ('n', '<f8')])

咱們須要記住,默認狀況下,dtype=float所以,對於第二列指望浮點數。可是,字符串'2.3%'78.9% >沒法轉換爲浮點數,咱們最終改成使用np.nan讓咱們如今使用轉換器:

>>> # Converted case ...
>>> np.genfromtxt(BytesIO(data), delimiter=",", names=names,
...              converters={1: convertfunc})
array([(1.0, 0.023, 45.0), (6.0, 0.78900000000000003, 0.0)],
     dtype=[('i', '<f8'), ('p', '<f8'), ('n', '<f8')])

使用第二列的名稱("p")做爲鍵而不是索引(1)能夠得到相同的結果:

 

>>> # Using a name for the converter ...
>>> np.genfromtxt(BytesIO(data), delimiter=",", names=names,
...              converters={"p": convertfunc})
array([(1.0, 0.023, 45.0), (6.0, 0.78900000000000003, 0.0)],
     dtype=[('i', '<f8'), ('p', '<f8'), ('n', '<f8')])

 

轉換器還可用於爲缺乏的條目提供默認值。在如下示例中,轉換器convert將剝離的字符串轉換爲相應的浮點型或若是字符串爲空,轉換爲-999。咱們須要從空格中顯式刪除字符串,由於它不是默認作的:

>>> data = "1, , 3\n 4, 5, 6"
>>> convert = lambda x: float(x.strip() or -999)
>>> np.genfromtxt(BytesIO(data), delimiter=",",
...              converters={1: convert})
array([[   1., -999.,    3.],
      [   4.,    5.,    6.]])

使用 missing 和 filling values

在咱們嘗試導入的數據集中可能會丟失某些條目。在前面的示例中,咱們使用轉換器將空字符串轉換爲浮點數。然而,用戶定義的轉換器可能迅速地變得難以管理。

genfromtxt函數提供了另外兩個補充機制:missing_values參數用於識別丟失的數據,第二個參數filling_values這些丟失的數據。

missing_values

默認狀況下,任何空字符串都標記爲缺乏。咱們還能夠考慮更復雜的字符串,例如"N/A""???"以表示丟失或無效的數據。missing_values參數接受三種類型的值:

  • 一個字符串或逗號分隔的字符串

  • 此字符串將用做全部列的缺乏數據的標記

  • 字符串序列

  • 在這種狀況下,每一個項目按順序與列相關聯。

  • 一本字典

字典的值是字符串或字符串序列。相應的鍵能夠是列索引(整數)或列名(字符串)。此外,特殊鍵None可用於定義適用於全部列的默認值。

filling_values

咱們知道如何識別丟失的數據,但咱們仍然須要爲這些丟失的條目提供一個值。默認狀況下,此值根據此表從預期的dtype肯定:

預期類型

默認

   

bool

False

int

-1

float

np.nan

complex

np.nan+0j

string

'???'

咱們可使用filling_values可選參數對缺失值的轉換進行更精細的控制。missing_values同樣,此參數接受不一樣類型的值:

  • 單個值

  • 這將是全部列的默認值

  • 一個值序列

  • 每一個條目將是相應列的默認值

  • 一本字典

每一個鍵能夠是列索引或列名,而且相應的值應該是單個對象。咱們可使用特殊鍵None爲全部列定義默認值。

在下面的例子中,咱們假設缺乏的值在第一列中用"N/A"標記,"???"在第三列。咱們但願將這些缺失值轉換爲0,若是它們出如今第一列和第二列中,則轉換爲-999,若是它們出如今最後一列中:

>>> data = "N/A, 2, 3\n4, ,???"
>>> kwargs = dict(delimiter=",",
...              dtype=int,
...              names="a,b,c",
...              missing_values={0:"N/A", 'b':" ", 2:"???"},
...              filling_values={0:0, 'b':0, 2:-999})
>>> np.genfromtxt(BytesIO(data), **kwargs)
array([(0, 2, 3), (4, 0, -999)],
     dtype=[('a', '<i8'), ('b', '<i8'), ('c', '<i8')])

usemask

咱們還可能但願經過構造布爾掩碼來跟蹤丟失數據的出現,其中缺乏數據的True條目,不然False爲此,咱們只須要將可選參數usemask設置爲True(默認值爲False)。輸出數組將是MaskedArray

Shortcut functions

除了genfromtxtnumpy.lib.io模塊提供了從genfromtxt派生的幾個方便函數。這些函數的工做方式與原始函數相同,但它們具備不一樣的默認值。

  • ndfromtxt
  • 始終設置usemask=False輸出始終爲標準numpy.ndarray
  • mafromtxt
  • 始終設置usemask=True輸出始終爲MaskedArray
  • recfromtxt
  • 返回標準numpy.recarray(if usemask=False)或MaskedRecords數組(若是usemaske=True默認dtype爲dtype=None,表示每一個列的類型將自動肯定。
  • recfromcsv
  • 相似於recfromtxt,但使用默認的delimiter=","
相關文章
相關標籤/搜索