2012-03-19 132 views
6

我想知道标准化numpy recarray的最佳方法是什么。为了说清楚,我不是在谈论一个数学矩阵,而是一个记录数组,它也有例如文本列(如标签)。标准化/标准化numpy recarray

a = np.genfromtxt("iris.csv", delimiter=",", dtype=None) 
print a.shape 
> (150,) 

正如你所看到的,我不能过程a[:,:-1],因为形状是一维的。

我找到的最好的是遍历所有列:

for nam in a.dtype.names[:-1]: 
    col = a[nam] 
    a[nam] = (col - col.min())/(col.max() - col.min()) 

这样做的任何更优雅的方式?有什么方法可以在某处“标准化”或“标准化”吗?

回答

6

有很多方法可以做到,但有些方法比其他方法更清洁。

通常,在numpy中,您将字符串数据保存在单独的数组中。

(事情有点多级低比,也就是说,R的数据帧。通常,只需换东西了在该协会的一类,但保持不同的数据类型分开。)

老实说,numpy的ISN没有针对这种处理“灵活”数据类型进行优化(虽然它当然可以做到)。诸如pandas之类的东西为“类似电子表格”的数据提供了更好的接口(而熊猫只是numpy之上的一层)。

然而,结构化数组(这是你在这里所能得到的)将允许你在传递字段名列表时按字段对它们进行切片。 (例如data[['col1', 'col2', 'col3']]

无论如何,一个办法就是做这样的事情:

import numpy as np 

data = np.recfromcsv('iris.csv') 

# In this case, it's just all but the last, but we could be more general 
# This must be a list and not a tuple, though. 
float_fields = list(data.dtype.names[:-1]) 

float_dat = data[float_fields] 

# Now we just need to view it as a "regular" 2D array... 
float_dat = float_dat.view(np.float).reshape((data.size, -1)) 

# And we can normalize columns as usual. 
normalized = (float_dat - float_dat.min(axis=0))/float_dat.ptp(axis=0) 

然而,这是很不理想。如果您想在原地进行操作(就像您现在所做的那样),最简单的解决方案就是您已有的操作:只需遍历字段名称即可。

顺便说一句,使用pandas,你会做这样的事情:

import pandas 
data = pandas.read_csv('iris.csv', header=None) 

float_dat = data[data.columns[:-1]] 
dmin, dmax = float_dat.min(axis=0), float_dat.max(axis=0) 

data[data.columns[:-1]] = (float_dat - dmin)/(dmax - dmin) 
+1

+1谢谢。这是一个非常丰富和有见地的答案。将数据集分成数字列和非数字列可能是一条可行的路线。这使得许多其他操作的定义非常清晰,实际上我正在尝试这么做。我没有意识到使用'data [list]'选择多个列的选项。 – 2012-03-20 07:02:53

1

什么版本的NumPy的您使用的是?在版本1.5.1中,我没有得到这种行为。我做了一个简短的文本文件为例,保存为test.txt

last,first,country,state,zip 
tyson,mike,USA,Nevada,89146 
brady,tom,USA,Massachusetts,02035 

当我再执行下面的代码,这是我得到:

>>> import numpy as np 
>>> a = np.genfromtxt("/home/ely/Desktop/Python/test.txt",delimiter=',',dtype=None) 
>>> print a.shape 
(3,5) 
>>> print a 
[['last' 'first' 'country' 'state' 'zip'] 
['tyson' 'mike' 'USA' 'Nevada' '89146'] 
['brady' 'tom' 'USA' 'Massachusetts' '02035']] 
>>> print a[0,:-1] 
['last' 'first' 'country' 'state'] 
>>> print a.dtype.names 
None 

我只是想知道什么是关于不同你的数据。

+0

注意:这是作为评论,而不是答案......只是需要更多空间放在上面的示例中。 – ely 2012-03-19 18:59:32

+0

不同之处在于,您得到的是字符串数组,而不是结构化数组。在你的例子中看看'a'的dtype。 – 2012-03-19 19:07:54

+0

当然,但是导致传入数组“结构化”的原因是什么?如果它只是一个csv文件,'genfromtxt()'总是不会产生一个字符串数组? – ely 2012-03-19 19:10:09