NumPy 提供了幾個(gè)函數(shù)來(lái)從表格數(shù)據(jù)創(chuàng)建數(shù)組。我們?cè)谶@里重點(diǎn)介紹genfromtxt
功能。
簡(jiǎn)而言之,genfromtxt
運(yùn)行兩個(gè)主循環(huán)。第一個(gè)循環(huán)將文件的每一行轉(zhuǎn)換為字符串序列。第二個(gè)循環(huán)將每個(gè)字符串轉(zhuǎn)換為適當(dāng)?shù)臄?shù)據(jù)類(lèi)型。這種機(jī)制比單個(gè)循環(huán)慢,但提供了更大的靈活性。特別是,?genfromtxt
能夠?qū)G失的數(shù)據(jù)考慮在內(nèi),而其他更快、更簡(jiǎn)單的功能如loadtxt
不能。
的唯一強(qiáng)制性參數(shù)genfromtxt
是數(shù)據(jù)的來(lái)源。它可以是字符串、字符串列表、生成器或帶有read
方法的打開(kāi)的類(lèi)文件對(duì)象,例如文件或?io.StringIO
對(duì)象。如果提供單個(gè)字符串,則假定它是本地或遠(yuǎn)程文件的名稱(chēng)。如果提供了字符串列表或返回字符串的生成器,則每個(gè)字符串都被視為文件中的一行。當(dāng)傳入遠(yuǎn)程文件的 URL 時(shí),該文件會(huì)自動(dòng)下載到當(dāng)前目錄并打開(kāi)。
識(shí)別的文件類(lèi)型是文本文件和檔案。目前,該功能可識(shí)別gzip
和bz2
(?bzip2
) 檔案。存檔的類(lèi)型由文件的擴(kuò)展名決定:如果文件名以 結(jié)尾'.gz'
,則需要gzip
存檔;如果以 結(jié)尾?'bz2'
,bzip2
則假定為存檔。
delimiter
參數(shù)一旦文件被定義并打開(kāi)以供讀取,genfromtxt
?將每個(gè)非空行拆分為一系列字符串??招谢蜃⑨屝袝?huì)被跳過(guò)。該delimiter
關(guān)鍵字用來(lái)定義分割應(yīng)該如何發(fā)生。
通常,單個(gè)字符標(biāo)志著列之間的分隔。例如,逗號(hào)分隔文件 (CSV) 使用逗號(hào) (?,
) 或分號(hào) (?;
) 作為分隔符:
>>> data = u"1, 2, 3\n4, 5, 6"
>>> np.genfromtxt(StringIO(data), delimiter=",")
array([[ 1., 2., 3.],
[ 4., 5., 6.]])
另一個(gè)常見(jiàn)的分隔符是"\t"
制表符。但是,我們不限于單個(gè)字符,任何字符串都可以。默認(rèn)情況下,?genfromtxt
假設(shè)delimiter=None
,這意味著該行沿空格(包括制表符)拆分,并且連續(xù)的空格被視為單個(gè)空格。
或者,我們可能正在處理一個(gè)固定寬度的文件,其中列被定義為給定數(shù)量的字符。在這種情況下,我們需要設(shè)置?delimiter
為單個(gè)整數(shù)(如果所有列的大小相同)或整數(shù)序列(如果列可以具有不同的大?。?/p>
>>> data = u" 1 2 3\n 4 5 67\n890123 4"
>>> np.genfromtxt(StringIO(data), delimiter=3)
array([[ 1., 2., 3.],
[ 4., 5., 67.],
[ 890., 123., 4.]])
>>> data = u"123456789\n 4 7 9\n 4567 9"
>>> np.genfromtxt(StringIO(data), delimiter=(4, 3, 2))
array([[ 1234., 567., 89.],
[ 4., 7., 9.],
[ 4., 567., 9.]])
autostrip
參數(shù)默認(rèn)情況下,當(dāng)一行被分解為一系列字符串時(shí),不會(huì)去除單個(gè)條目的前導(dǎo)空格和尾隨空格??梢酝ㄟ^(guò)將可選參數(shù)設(shè)置autostrip
為以下值來(lái)覆蓋此行為?True
:
>>> data = u"1, abc , 2\n 3, xxx, 4"
>>> # Without autostrip
>>> np.genfromtxt(StringIO(data), delimiter=",", dtype="|U5")
array([['1', ' abc ', ' 2'],
['3', ' xxx', ' 4']], dtype='<U5')
>>> # With autostrip
>>> np.genfromtxt(StringIO(data), delimiter=",", dtype="|U5", autostrip=True)
array([['1', 'abc', '2'],
['3', 'xxx', '4']], dtype='<U5')
comments
參數(shù)可選參數(shù)comments
用于定義標(biāo)記注釋開(kāi)頭的字符串。默認(rèn)情況下,?genfromtxt
假設(shè)comments='#'
.?注釋標(biāo)記可能出現(xiàn)在該行的任何位置。注釋標(biāo)記之后出現(xiàn)的任何字符都將被忽略:
>>> data = u"""#
... # 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(StringIO(data), comments="#", delimiter=",")
array([[1., 2.],
[3., 4.],
[5., 6.],
[7., 8.],
[9., 0.]])
1.7.0 新版功能:當(dāng)comments
設(shè)置為 時(shí)None
,不會(huì)將任何行視為注釋。
這種行為有一個(gè)值得注意的例外:如果可選參數(shù)?names=True
,將檢查第一個(gè)注釋行的名稱(chēng)。
skip_header
和skip_footer
參數(shù)文件中標(biāo)頭的存在會(huì)阻礙數(shù)據(jù)處理。在這種情況下,我們需要使用skip_header
可選參數(shù)。此參數(shù)的值必須是一個(gè)整數(shù),它對(duì)應(yīng)于在執(zhí)行任何其他操作之前要在文件開(kāi)頭跳過(guò)的行數(shù)。類(lèi)似地,我們可以n
通過(guò)使用skip_footer
屬性并為其賦予值來(lái)跳過(guò)文件的最后幾行n
:
>>> data = u"\n".join(str(i) for i in range(10))
>>> np.genfromtxt(StringIO(data),)
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
>>> np.genfromtxt(StringIO(data),
... skip_header=3, skip_footer=5)
array([ 3., 4.])
默認(rèn)情況下,skip_header=0
和skip_footer=0
,意味著不跳過(guò)任何行。
usecols
參數(shù)在某些情況下,我們并不對(duì)數(shù)據(jù)的所有列感興趣,而只對(duì)其中的幾列感興趣。我們可以使用usecols
參數(shù)選擇要導(dǎo)入的列?。此參數(shù)接受與要導(dǎo)入的列的索引對(duì)應(yīng)的單個(gè)整數(shù)或整數(shù)序列。請(qǐng)記住,按照慣例,第一列的索引為 0。負(fù)整數(shù)的行為與常規(guī) Python 負(fù)索引相同。
例如,如果我們只想導(dǎo)入第一列和最后一列,我們可以使用:usecols=(0,?-1)
>>> data = u"1 2 3\n4 5 6"
>>> np.genfromtxt(StringIO(data), usecols=(0, -1))
array([[ 1., 3.],
[ 4., 6.]])
如果列有名稱(chēng),我們還可以通過(guò)將名稱(chēng)作為usecols
參數(shù)的名稱(chēng)作為字符串序列或逗號(hào)分隔的字符串來(lái)選擇要導(dǎo)入的列:
>>> data = u"1 2 3\n4 5 6"
>>> np.genfromtxt(StringIO(data),
... names="a, b, c", usecols=("a", "c"))
array([(1.0, 3.0), (4.0, 6.0)],
dtype=[('a', '<f8'), ('c', '<f8')])
>>> np.genfromtxt(StringIO(data),
... names="a, b, c", usecols=("a, c"))
array([(1.0, 3.0), (4.0, 6.0)],
dtype=[('a', '<f8'), ('c', '<f8')])
控制我們從文件中讀取的字符串序列如何轉(zhuǎn)換為其他類(lèi)型的主要方法是設(shè)置dtype
參數(shù)。此參數(shù)可接受的值為:
單一類(lèi)型,例如dtype=float
.?輸出將是具有給定 dtype 的 2D,除非使用names
參數(shù)將名稱(chēng)與每列關(guān)聯(lián)(見(jiàn)下文)。請(qǐng)注意,這dtype=float
是?genfromtxt
.
dtype=(int,?float,?float)
dtype="i4,f8,|U3"
.'names'
和的字典'formats'
。(name,?type)``dtype=[('A',?int),?('B',?float)]
numpy.dtype
對(duì)象。None
。在這種情況下,列的類(lèi)型將由數(shù)據(jù)本身確定(見(jiàn)下文)。
在除第一種情況之外的所有情況下,輸出將是具有結(jié)構(gòu)化 dtype 的一維數(shù)組。此 dtype 具有與序列中的項(xiàng)目一樣多的字段。字段名稱(chēng)是用names
關(guān)鍵字定義的。
當(dāng) 時(shí)dtype=None
,每列的類(lèi)型由其數(shù)據(jù)迭代確定。我們首先檢查字符串是否可以轉(zhuǎn)換為布爾值(即字符串是否匹配true
或false
小寫(xiě));然后它是否可以轉(zhuǎn)換為整數(shù),然后轉(zhuǎn)換為浮點(diǎn)數(shù),然后轉(zhuǎn)換為復(fù)數(shù),最終轉(zhuǎn)換為字符串??梢酝ㄟ^(guò)修改類(lèi)的默認(rèn)映射器來(lái)更改此行為?StringConverter
。
dtype=None
提供該選項(xiàng)是為了方便。但是,它比顯式設(shè)置 dtype 慢得多。
names
參數(shù)處理表格數(shù)據(jù)時(shí)的一種自然方法是為每一列分配一個(gè)名稱(chēng)。第一種可能性是使用顯式結(jié)構(gòu)化 dtype,如前所述:
>>> data = StringIO("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')])
另一種更簡(jiǎn)單的可能性是將names
關(guān)鍵字與字符串序列或逗號(hào)分隔的字符串一起使用:
>>> data = StringIO("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')])
在上面的例子中,我們使用了默認(rèn)情況下,dtype=float
.?通過(guò)給出一系列名稱(chēng),我們將輸出強(qiáng)制為結(jié)構(gòu)化 dtype。
我們有時(shí)可能需要從數(shù)據(jù)本身定義列名。在這種情況下,我們必須使用names
值為的關(guān)鍵字?True
。然后將從第一行(在skip_header
那些之后)讀取名稱(chēng)?,即使該行被注釋掉:
>>> data = StringIO("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')])
默認(rèn)值names
是None
。如果我們給關(guān)鍵字賦予任何其他值,新名稱(chēng)將覆蓋我們可能用 dtype 定義的字段名稱(chēng):
>>> data = StringIO("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
參數(shù)如果names=None
但需要結(jié)構(gòu)化 dtype,則使用標(biāo)準(zhǔn) NumPy 默認(rèn)值定義"f%i"
名稱(chēng),產(chǎn)生類(lèi)似 的名稱(chēng)f0
,?f1
依此類(lèi)推:
>>> data = StringIO("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')])
同樣,如果我們沒(méi)有給出足夠多的名稱(chēng)來(lái)匹配 dtype 的長(zhǎng)度,缺少的名稱(chēng)將使用這個(gè)默認(rèn)模板定義:
>>> data = StringIO("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
參數(shù)覆蓋這個(gè)默認(rèn)值,它接受任何格式字符串:
>>> data = StringIO("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
只有在預(yù)期某些名稱(chēng)但未定義時(shí)才使用它。
也可以將具有結(jié)構(gòu)化數(shù)據(jù)類(lèi)型的 NumPy 數(shù)組視為?recarray
,其中可以像訪問(wèn)屬性一樣訪問(wèn)字段。出于這個(gè)原因,我們可能需要確保字段名稱(chēng)不包含任何空格或無(wú)效字符,或者它不對(duì)應(yīng)于標(biāo)準(zhǔn)屬性的名稱(chēng)(如size
或?shape
),這會(huì)混淆解釋器。?genfromtxt
?接受三個(gè)可選參數(shù),可以更好地控制名稱(chēng):
deletechars
給出一個(gè)字符串,該字符串組合了必須從名稱(chēng)中刪除的所有字符。默認(rèn)情況下,無(wú)效字符為?.~!@#$%^&*()-=+~\|]}[{';:?/?.>,<
excludelist
給出要排除的名稱(chēng)列表,例如return
,?file
,?print
... 如果輸入名稱(chēng)之一是此列表的一部分,'_'
則將在其后附加下劃線字符 (?)。case_sensitive
名稱(chēng)是否應(yīng)區(qū)分大小寫(xiě) (?case_sensitive=True
)、轉(zhuǎn)換為大寫(xiě) (case_sensitive=False
或?case_sensitive='upper'
) 或小寫(xiě) (?case_sensitive='lower'
)。converters
參數(shù)通常,定義 dtype 足以定義必須如何轉(zhuǎn)換字符串序列。然而,有時(shí)可能需要一些額外的控制。例如,我們可能希望確保將某種格式的日期?YYYY/MM/DD
轉(zhuǎn)換為datetime
對(duì)象,或者將類(lèi)似字符串xx%
正確轉(zhuǎn)換為介于 0 和 1 之間的浮點(diǎn)數(shù)。在這種情況下,我們應(yīng)該使用converters
?參數(shù)定義轉(zhuǎn)換函數(shù)。
此參數(shù)的值通常是一個(gè)字典,其中列索引或列名作為鍵,轉(zhuǎn)換函數(shù)作為值。這些轉(zhuǎn)換函數(shù)可以是實(shí)際函數(shù)或 lambda 函數(shù)。在任何情況下,它們都應(yīng)該只接受一個(gè)字符串作為輸入,并且只輸出所需類(lèi)型的單個(gè)元素。
在以下示例中,第二列從表示百分比的字符串轉(zhuǎn)換為介于 0 和 1 之間的浮點(diǎn)數(shù):
>>> convertfunc = lambda x: float(x.strip(b"%"))/100.
>>> data = u"1, 2.3%, 45.\n6, 78.9%, 0"
>>> names = ("i", "p", "n")
>>> # General case .....
>>> np.genfromtxt(StringIO(data), delimiter=",", names=names)
array([(1., nan, 45.), (6., nan, 0.)],
dtype=[('i', '<f8'), ('p', '<f8'), ('n', '<f8')])
我們需要記住,默認(rèn)情況下,dtype=float
.?因此,預(yù)計(jì)第二列會(huì)出現(xiàn)浮點(diǎn)數(shù)。但是,字符串?和不能轉(zhuǎn)換為浮點(diǎn)數(shù),我們最終得到了??,F(xiàn)在讓我們使用轉(zhuǎn)換器:'?2.3%'``'?78.9%'``np.nan
>>> # Converted case ...
>>> np.genfromtxt(StringIO(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')])
使用第二列的名稱(chēng) (?"p"
) 作為鍵而不是其索引 (1)可以獲得相同的結(jié)果:
>>> # Using a name for the converter ...
>>> np.genfromtxt(StringIO(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')])
轉(zhuǎn)換器還可用于為丟失的條目提供默認(rèn)值。在以下示例中,convert
如果字符串為空,轉(zhuǎn)換器將剝離的字符串轉(zhuǎn)換為相應(yīng)的浮點(diǎn)數(shù)或 -999。我們需要從空格中顯式地去除字符串,因?yàn)槟J(rèn)情況下不這樣做:
>>> data = u"1, , 3\n 4, 5, 6"
>>> convert = lambda x: float(x.strip() or -999)
>>> np.genfromtxt(StringIO(data), delimiter=",",
... converters={1: convert})
array([[ 1., -999., 3.],
[ 4., 5., 6.]])
我們嘗試導(dǎo)入的數(shù)據(jù)集中可能缺少某些條目。在前面的示例中,我們使用轉(zhuǎn)換器將空字符串轉(zhuǎn)換為浮點(diǎn)數(shù)。然而,用戶定義的轉(zhuǎn)換器可能很快變得難以管理。
該genfromtxt
函數(shù)提供了另外兩種補(bǔ)充機(jī)制:missing_values
參數(shù)用于識(shí)別缺失數(shù)據(jù),第二個(gè)參數(shù)filling_values
用于處理這些缺失數(shù)據(jù)。
missing_values
默認(rèn)情況下,任何空字符串都被標(biāo)記為缺失。我們還可以考慮更復(fù)雜的字符串,例如"N/A"
或"???"
來(lái)表示丟失或無(wú)效的數(shù)據(jù)。該missing_values
參數(shù)接受三個(gè)類(lèi)型的值:
None
可用于定義適用于所有列的默認(rèn)值。filling_values
我們知道如何識(shí)別缺失的數(shù)據(jù),但我們?nèi)匀恍枰獮檫@些缺失的條目提供一個(gè)值。默認(rèn)情況下,此值是根據(jù)下表根據(jù)預(yù)期的 dtype 確定的:
預(yù)期類(lèi)型 | 默認(rèn) |
---|---|
bool |
False |
int |
-1 |
float |
np.nan |
complex |
np.nan+0j |
string |
'???' |
我們可以使用filling_values
可選參數(shù)更好地控制缺失值的轉(zhuǎn)換?。就像?missing_values
,這個(gè)參數(shù)接受不同類(lèi)型的值:
None
為所有列定義默認(rèn)值。
在下面的示例中,我們假設(shè)缺失值"N/A"
在第一列中標(biāo)記為 with?,"???"
在第三列中標(biāo)記為by?。如果它們出現(xiàn)在第一列和第二列,我們希望將這些缺失值轉(zhuǎn)換為 0,如果它們出現(xiàn)在最后一列,則轉(zhuǎn)換為 -999:
>>> data = u"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(StringIO(data), **kwargs)
array([(0, 2, 3), (4, 0, -999)],
dtype=[('a', '<i8'), ('b', '<i8'), ('c', '<i8')])
usemask
我們可能還想通過(guò)構(gòu)建一個(gè)布爾掩碼來(lái)跟蹤丟失數(shù)據(jù)的發(fā)生情況,True
其中包含數(shù)據(jù)丟失的條目等False
。為此,我們只需將可選參數(shù)設(shè)置usemask
為True
(默認(rèn)為False
)。輸出數(shù)組將是一個(gè)MaskedArray
.
此外genfromtxt
,該numpy.lib.npyio
模塊提供了幾個(gè)從?genfromtxt
.?這些函數(shù)的工作方式與原始函數(shù)相同,但它們具有不同的默認(rèn)值。
recfromtxt
返回標(biāo)準(zhǔn)numpy.recarray
(if?usemask=False
) 或?MaskedRecords
數(shù)組 (if?usemaske=True
)。默認(rèn)的 dtype 是dtype=None
,這意味著將自動(dòng)確定每列的類(lèi)型。recfromcsv
喜歡recfromtxt
,但有一個(gè)默認(rèn)值delimiter=","
。
更多建議: