首页 文章

将pandas数据帧转换为numpy数组,保留索引

提问于
浏览
200

我有兴趣知道如何将pandas数据帧转换为numpy数组,包括索引,并设置dtypes .

数据帧:

import numpy as np
import pandas as pd

index = [1, 2, 3, 4, 5, 6, 7]
a = [np.nan, np.nan, np.nan, 0.1, 0.1, 0.1, 0.1]
b = [0.2, np.nan, 0.2, 0.2, 0.2, np.nan, np.nan]
c = [np.nan, 0.5, 0.5, np.nan, 0.5, 0.5, np.nan]
df = pd.DataFrame({'A': a, 'B': b, 'C': c}, index=index)
df = df.rename_axis('ID')

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')])

(或类似的)

有关如何实现这一目标的任何建议? (我不知道此时我是否需要1D或2D阵列 . )我已经看到了一些涉及这个的帖子,但没有专门处理dataframe.index .

我正在使用to_csv编写数据帧磁盘(并将其读回来创建数组)作为一种解决方法,但我更喜欢比我的新熊猫kludging更有说服力的东西 .

11 回答

  • 5

    要将pandas数据帧(df)转换为numpy ndarray,请使用以下代码:

    df = df.values

    df现在成为numpy ndarray:

    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]])
    
  • 53

    熊猫有内置的东西......

    numpy_matrix = df.as_matrix()
    

    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]])
    
  • 20

    我只是链接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]])
    

    要获得dtypes,我们需要使用view将此ndarray转换为结构化数组:

    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

    从dataframe导出到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')]))
    
  • 9

    您可以使用 to_records 方法,但如果它们不是您想要的,那么必须使用dtypes . 在我的例子中,从字符串复制DF后,索引类型是字符串(由pandas中的 object dtype表示):

    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 dtype对我来说不起作用,但是已经可以在Pandas中执行此操作:

    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')])
    

    请注意,Pandas没有在导出的记录数组中正确设置索引的名称(到 ID )(一个错误?),所以我们从类型转换中获益也是为了纠正它 .

    目前,Pandas只有8字节的整数, i8 和浮点数, f8 (见这个issue) .

  • 28

    好像 df.to_records() 会对你有用 . 您正在寻找的确切功能was requestedto_records 作为替代方案 .

    我在本地使用你的例子尝试了这个,并且该调用产生的东西与你正在寻找的输出非常相似:

    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=[(u'ID', '<i8'), (u'A', '<f8'), (u'B', '<f8'), (u'C', '<f8')])
    

    请注意,这是 recarray 而不是 array . 您可以通过将其构造函数调用为 np.array(df.to_records()) 将结果移动到常规numpy数组中 .

  • 204

    这是我从pandas DataFrame制作结构数组的方法 .

    创建数据框

    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
    

    定义函数以从pandas DataFrame创建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的评论和解决方案 .

  • 104

    将数据帧转换为Numpy数组表示的两种方法 .

    • mah_np_array = df.as_matrix(columns=None)

    • mah_np_array = df.values

    Doc:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.as_matrix.html

  • 3

    继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))
    
  • 3

    示例DataFrame的简单方法:df

    df =
             gbm       nnet        reg
    0  12.097439  12.047437  12.100953
    1  12.109811  12.070209  12.095288
    2  11.720734  11.622139  11.740523
    3  11.824557  11.926414  11.926527
    4  11.800868  11.727730  11.729737
    5  12.490984  12.502440  12.530894
    

    使用:

    np.array(df.to_records().view(type=np.matrix))
    

    得到:

    array([[(0, 12.097439  , 12.047437, 12.10095324),
            (1, 12.10981081, 12.070209, 12.09528824),
            (2, 11.72073428, 11.622139, 11.74052253),
            (3, 11.82455653, 11.926414, 11.92652727),
            (4, 11.80086775, 11.72773 , 11.72973699),
            (5, 12.49098389, 12.50244 , 12.53089367)]],
    dtype=(numpy.record, [('index', '<i8'), ('gbm', '<f8'), ('nnet', '<f4'),
           ('reg', '<f8')]))
    
  • 2

    感谢Phil的回答,这很棒 .

    回复

    对我不起作用,错误:TypeError:数据类型不明白 - Joseph Garvin 2月13日17:55

    我使用python 3,并得到相同的错误 . 然后我删除.encode(),然后表达式如下 .

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

    然后它工作 .

相关问题