2012-11-02 75 views
117

我有兴趣了解如何将熊猫数据框转换为包含索引的numpy数组,并设置dtypes。将熊猫数据框转换为numpy数组,保留索引

数据框:

label A B C 
ID         
1 NaN 0.2 NaN 
2 NaN NaN 0.5 
3 NaN 0.2 0.5 
4 0.1 0.2 NaN 
5 0.1 0.2 0.5 
6 0.1 NaN 0.5 
7 0.1 NaN NaN 

转换DF数组回报:

array([[ nan, 0.2, nan], 
     [ nan, nan, 0.5], 
     [ nan, 0.2, 0.5], 
     [ 0.1, 0.2, nan], 
     [ 0.1, 0.2, 0.5], 
     [ 0.1, nan, 0.5], 
     [ 0.1, nan, nan]]) 

不过,我想:

array([[ 1, nan, 0.2, nan], 
     [ 2, nan, nan, 0.5], 
     [ 3, nan, 0.2, 0.5], 
     [ 4, 0.1, 0.2, nan], 
     [ 5, 0.1, 0.2, 0.5], 
     [ 6, 0.1, nan, 0.5], 
     [ 7, 0.1, nan, nan]], 
    dtype=[('ID', '<i4'), ('A', '<f8'), ('B', '<f8'), ('B', '<f8')]) 

(或类似)

任何建议上如何成就这个? (我不知道我是否需要一维或二维数组)。我已经看过几篇涉及这个问题的文章,但没有涉及到dataframe.index的具体内容。

我正在使用to_csv编写数据帧磁盘(并将其读回以创建数组),但我宁愿选择比我的新到熊猫更为雄辩的东西。

回答

22

你可以使用to_records方法,但是如果它们不是你想要的,就必须使用dtypes。就我而言,已经从一个字符串复制你的DF,索引类型为字符串(在大熊猫的object D型为代表):

In [102]: df 
Out[102]: 
label A B C 
ID     
1  NaN 0.2 NaN 
2  NaN NaN 0.5 
3  NaN 0.2 0.5 
4  0.1 0.2 NaN 
5  0.1 0.2 0.5 
6  0.1 NaN 0.5 
7  0.1 NaN NaN 

In [103]: df.index.dtype 
Out[103]: dtype('object') 
In [104]: df.to_records() 
Out[104]: 
rec.array([(1, nan, 0.2, nan), (2, nan, nan, 0.5), (3, nan, 0.2, 0.5), 
     (4, 0.1, 0.2, nan), (5, 0.1, 0.2, 0.5), (6, 0.1, nan, 0.5), 
     (7, 0.1, nan, nan)], 
     dtype=[('index', '|O8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 
In [106]: df.to_records().dtype 
Out[106]: dtype([('index', '|O8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 

转换的recarray D型,我不工作,而是一个可以做到这一点熊猫已经:

In [109]: df.index = df.index.astype('i8') 
In [111]: df.to_records().view([('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 
Out[111]: 
rec.array([(1, nan, 0.2, nan), (2, nan, nan, 0.5), (3, nan, 0.2, 0.5), 
     (4, 0.1, 0.2, nan), (5, 0.1, 0.2, 0.5), (6, 0.1, nan, 0.5), 
     (7, 0.1, nan, nan)], 
     dtype=[('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 

注意,大熊猫不导出记录阵列(错误?)中正确设置索引的名称(以ID),所以我们从类型转换也是正确的为获利。

目前Pandas只有8字节整数,i8和浮点数,f8(请参阅此issue)。

+2

要获得抢手的结构数组(具有比recarray更好的性能),您只需通过recarray到'np.array'构造函数。 – meteore

+0

索引名称错误:https://github.com/pydata/pandas/issues/2161 –

+0

我们只是修复了上面显示的索引名称。 –

30

我只想链DataFrame.reset_index()DataFrame.values函数来获取数据框的numpy的代表性,包括索引:

In [8]: df 
Out[8]: 
      A   B   C 
0 -0.982726 0.150726 0.691625 
1 0.617297 -0.471879 0.505547 
2 0.417123 -1.356803 -1.013499 
3 -0.166363 -0.957758 1.178659 
4 -0.164103 0.074516 -0.674325 
5 -0.340169 -0.293698 1.231791 
6 -1.062825 0.556273 1.508058 
7 0.959610 0.247539 0.091333 

[8 rows x 3 columns] 

In [9]: df.reset_index().values 
Out[9]: 
array([[ 0.  , -0.98272574, 0.150726 , 0.69162512], 
     [ 1.  , 0.61729734, -0.47187926, 0.50554728], 
     [ 2.  , 0.4171228 , -1.35680324, -1.01349922], 
     [ 3.  , -0.16636303, -0.95775849, 1.17865945], 
     [ 4.  , -0.16410334, 0.0745164 , -0.67432474], 
     [ 5.  , -0.34016865, -0.29369841, 1.23179064], 
     [ 6.  , -1.06282542, 0.55627285, 1.50805754], 
     [ 7.  , 0.95961001, 0.24753911, 0.09133339]]) 

为了得到我们需要使用这个ndarray转变为一个结构数组的dtypes view

In [10]: df.reset_index().values.ravel().view(dtype=[('index', int), ('A', float), ('B', float), ('C', float)]) 
Out[10]: 
array([(0, -0.98272574, 0.150726 , 0.69162512), 
     (1, 0.61729734, -0.47187926, 0.50554728), 
     (2, 0.4171228 , -1.35680324, -1.01349922), 
     (3, -0.16636303, -0.95775849, 1.17865945), 
     (4, -0.16410334, 0.0745164 , -0.67432474), 
     (5, -0.34016865, -0.29369841, 1.23179064), 
     (6, -1.06282542, 0.55627285, 1.50805754), 
     (7, 0.95961001, 0.24753911, 0.09133339), 
     dtype=[('index', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 
+1

这应该被标记为完整的答案,然后... – durbachit

+1

这个答案中唯一缺少的是如何从数据框中构造dtype,以便您可以编写通用函数 –

77

大熊猫已建成的东西在...

numpyMatrix = df.as_matrix() 
+15

这不会给出结构化数组,所有列是dtype'object'。 – sebix

7

这里是我从一个熊猫数据框制作结构数组的方法。

创建数据帧

import pandas as pd 
import numpy as np 
import six 

NaN = float('nan') 
ID = [1, 2, 3, 4, 5, 6, 7] 
A = [NaN, NaN, NaN, 0.1, 0.1, 0.1, 0.1] 
B = [0.2, NaN, 0.2, 0.2, 0.2, NaN, NaN] 
C = [NaN, 0.5, 0.5, NaN, 0.5, 0.5, NaN] 
columns = {'A':A, 'B':B, 'C':C} 
df = pd.DataFrame(columns, index=ID) 
df.index.name = 'ID' 
print(df) 

     A B C 
ID    
1 NaN 0.2 NaN 
2 NaN NaN 0.5 
3 NaN 0.2 0.5 
4 0.1 0.2 NaN 
5 0.1 0.2 0.5 
6 0.1 NaN 0.5 
7 0.1 NaN NaN 

定义功能,使从一个数据帧熊猫一个numpy的结构阵列(未记录数组)。

def df_to_sarray(df): 
    """ 
    Convert a pandas DataFrame object to a numpy structured array. 
    This is functionally equivalent to but more efficient than 
    np.array(df.to_array()) 

    :param df: the data frame to convert 
    :return: a numpy structured array representation of df 
    """ 

    v = df.values 
    cols = df.columns 

    if six.PY2: # python 2 needs .encode() but 3 does not 
     types = [(cols[i].encode(), df[k].dtype.type) for (i, k) in enumerate(cols)] 
    else: 
     types = [(cols[i], df[k].dtype.type) for (i, k) in enumerate(cols)] 
    dtype = np.dtype(types) 
    z = np.zeros(v.shape[0], dtype) 
    for (i, k) in enumerate(z.dtype.names): 
     z[k] = v[:, i] 
    return z 

使用reset_index来创建一个新的数据框,其中包含索引作为其数据的一部分。将该数据帧转换为结构数组。

sa = df_to_sarray(df.reset_index()) 
sa 

array([(1L, nan, 0.2, nan), (2L, nan, nan, 0.5), (3L, nan, 0.2, 0.5), 
     (4L, 0.1, 0.2, nan), (5L, 0.1, 0.2, 0.5), (6L, 0.1, nan, 0.5), 
     (7L, 0.1, nan, nan)], 
     dtype=[('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 

编辑:更新df_to_sarray避免错误调用.encode()与Python 3.由于Joseph Garvinhalcyon他们的意见和解决方案。

+0

对我不起作用,错误:TypeError:数据类型不能理解 –

+0

感谢您的评论并致函[halcyon](https://stackoverflow.com/users/8035165/halcyon)进行更正。我更新了我的答案,所以我希望现在适合你。 – Phil

2

继meteore的答案,我发现代码

df.index = df.index.astype('i8') 

对我不起作用。所以我把我的代码放在这里,以方便其他人坚持这个问题。

city_cluster_df = pd.read_csv(text_filepath, encoding='utf-8') 
# the field 'city_en' is a string, when converted to Numpy array, it will be an object 
city_cluster_arr = city_cluster_df[['city_en','lat','lon','cluster','cluster_filtered']].to_records() 
descr=city_cluster_arr.dtype.descr 
# change the field 'city_en' to string type (the index for 'city_en' here is 1 because before the field is the row index of dataframe) 
descr[1]=(descr[1][0], "S20") 
newArr=city_cluster_arr.astype(np.dtype(descr)) 
109

要将大熊猫数据帧(DF)转换为numpy的ndarray,使用此代码:

df=df.values

现在DF成为numpy的ndarray。

+5

这不起作用,dtype仍然被删除(你失去了名字)。 –

+3

这不回答问题。 –

1

感谢菲尔的回答,这很好。

doesn't work for me, error: TypeError: data type not understood – Joseph Garvin Feb 13 at 17:55

答复我使用Python 3,并获得同样的错误。然后我删除.encode(),然后表达式如下。

types = [(cols[i], df[k].dtype.type) for (i, k) in enumerate(cols)] 

然后它工作。

+0

感谢您的纠正。我更新了上面的答案,使用六个包来避免python 3的'.encode()'。 – Phil

0

从数据框导出到arcgis表时遇到了类似的问题,并偶然发现了usgs的解决方案(https://my.usgs.gov/confluence/display/cdi/pandas.DataFrame+to+ArcGIS+Table)。 总之你的问题有一个类似的解决方案:

df 
Out[109]: 
     A B C 
ID    
1 NaN 0.2 NaN 
2 NaN NaN 0.5 
3 NaN 0.2 0.5 
4 0.1 0.2 NaN 
5 0.1 0.2 0.5 
6 0.1 NaN 0.5 
7 0.1 NaN NaN 

np_data = np.array(np.rec.fromrecords(df.values)) 
np_names = df.dtypes.index.tolist() 
np_data.dtype.names = tuple([name.encode('UTF8') for name in np_names]) 

np_data 
Out[113]: 
array([(nan, 0.2, nan), (nan, nan, 0.5), (nan, 0.2, 0.5), 
     (0.1, 0.2, nan), (0.1, 0.2, 0.5), (0.1, nan, 0.5), 
     (0.1, nan, nan)], 
     dtype=(numpy.record, [('A', '<f8'), ('B', '<f8'), ('C', '<f8')])) 
相关问题