2016-11-11 137 views
3

to this post的时候,我应该能够访问在ndarray列的名称作为a.dtype.names如何保持列名从熊猫转换为numpy的

Howevever,如果我转换大熊猫数据帧到ndarray与df.as_matrix()或df.values,则dtype.names字段为None。另外,如果我尝试列名分配到ndarray

X = pd.DataFrame(dict(age=[40., 50., 60.], sys_blood_pressure=[140.,150.,160.])) 
print X 
print type(X.as_matrix())# <type 'numpy.ndarray'> 
print type(X.as_matrix()[0]) # <type 'numpy.ndarray'> 

m = X.as_matrix() 
m.dtype.names = list(X.columns) 

我得到

ValueError: there are no fields defined 

UPDATE:

我在矩阵只需要持有的情况下,特别感兴趣单一类型(它是特定数字类型的ndarray),因为我也想使用cython进行优化。 (我怀疑numpy记录和结构化数组更难以处理,因为它们的输入更自由。)

真的,我只想维护通过科学计算的深层树的数组的column_name元数据,套件预测器。它的接口的.fit(X,y)和.predict(X)API不允许传递有关X和y对象之外的列标签的附加元数据。

+0

'X.as_matrix()'可能产生一个统一的数组,全部为int或float。特别是如果所有列都具有相同的类型。链接中描述的'dtype.names'适用于结构化数组,其中一个使用复合'dtype'。熊猫是否有关于创建结构化数组的任何内容? – hpaulj

+0

你打算如何处理这些列名?你的问题看起来像一个[“XY问题”](http://meta.stackexchange.com/a/66378)... – MaxU

+0

你应该显示'X'(或至少一部分),以及'X. as_matrix()。shape'和'X.as_matrix()。dtype'。 – hpaulj

回答

4

考虑一个DF,如下所示:

X = pd.DataFrame(dict(one=['Strawberry', 'Fields', 'Forever'], two=[1,2,3])) 
X 

enter image description here

提供元组作为输入到结构化阵列数据的列表:

arr_ip = [tuple(i) for i in X.as_matrix()] 

有序字段名列表:

dtyp = np.dtype(list(zip(X.dtypes.index, X.dtypes))) 

在这里,X.dtypes.index给你列名和X.dtypes其相应被再次统一到元组列表,并作为输入所要构建的D型元素dtypes。

arr = np.array(arr_ip, dtype=dtyp) 

给出:

arr 
# array([('Strawberry', 1), ('Fields', 2), ('Forever', 3)], 
#  dtype=[('one', 'O'), ('two', '<i8')]) 

arr.dtype.names 
# ('one', 'two') 
+1

耶!草莓 – piRSquared

+1

很酷。谢谢。但这是怎么回事:type(arr [0])给出 user48956

+0

做'arr [0]'给你'('Strawberry',1)'。正如你所看到的,它们分别形成了一个'dtypes'组合的元组,即''str'和'np.int64'。 'np.void'基本上意味着这些数据类型不属于预定义的类型,例如* int/float/bool/str/cfloat *,而是形成一个集合,而其类型也必须被区分。因此,这些有时是称为灵活/通用数据类型。 –

0

OK,在这儿,我倾向于:

class NDArrayWithColumns(np.ndarray): 
    def __new__(cls, obj, columns=None): 
     obj = obj.view(cls) 
     obj.columns = columns 
     return obj 

    def __array_finalize__(self, obj): 
     if obj is None: return 
     self.columns = getattr(obj, 'columns', None) 

    @staticmethod 
    def from_dataframe(df): 
     cols = tuple(df.columns) 
     arr = df.as_matrix(cols) 
     return NDArrayWithColumns.from_array(arr,cols) 

    @staticmethod 
    def from_array(array,columns): 
     if isinstance(array,NDArrayWithColumns): 
      return array 
     return NDArrayWithColumns(array,tuple(columns)) 

    def __str__(self): 
     sup = np.ndarray.__str__(self) 
     if self.columns: 
      header = ", ".join(self.columns) 
      header = "# " + header + "\n" 
      return header+sup 
     return sup 

NAN = float("nan") 
X = pd.DataFrame(dict(age=[40., NAN, 60.], sys_blood_pressure=[140.,150.,160.])) 
arr = NDArrayWithColumns.from_dataframe(X) 
print arr 
print arr.columns 
print arr.dtype 

给出:

# age, sys_blood_pressure 
[[ 40. 140.] 
[ nan 150.] 
[ 60. 160.]] 
('age', 'sys_blood_pressure') 
float64 

并且还可以传递给需要ndarray [2,double_t]的类型的cython函数。

更新:这个工程相当不错,除了一些oddness when passing the type to ufuncs

1

熊猫的数据框也有一个方便的方法to_records。演示:

X = pd.DataFrame(dict(age=[40., 50., 60.], 
         sys_blood_pressure=[140.,150.,160.])) 
m = X.to_records(index=False) 
print repr(m) 

返回:

rec.array([(40.0, 140.0), (50.0, 150.0), (60.0, 160.0)], 
      dtype=[('age', '<f8'), ('sys_blood_pressure', '<f8')]) 

这是一个"record array",这是一个子类ndarray允许字段访问使用属性,例如m.age以及m['age']

您可以通过构建一个视图作为常规float数组它传递给一个用Cython功能:

m_float = m.view(float).reshape(m.shape + (-1,)) 
print repr(m_float) 

其中给出:

rec.array([[ 40., 140.], 
      [ 50., 150.], 
      [ 60., 160.]], 
      dtype=float64) 

注为了这个工作,原来的数据帧每列必须有一个float dtype。确保使用m = X.astype(float, copy=False).to_records(index=False)