将pandas数据框转换为NumPy数组


465

我对知道如何将熊猫数据框转换为NumPy数组感兴趣。

数据框:

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

我想将其转换为NumPy数组,如下所示:

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?

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

或类似的?


5
为什么需要这个?反正不是基于numpy数组的数据帧吗?您应该能够在需要numpy数组的地方使用数据框。这就是为什么您可以在scikit-learn中使用数据框的原因,其中函数需要numpy数组。
基督

这里有几个约dtypes&recarrays(又名记录阵列或结构数组)可能相关链接:(1)stackoverflow.com/questions/9949427/... (2) stackoverflow.com/questions/52579601/...
强尼

注意:必须像这样将Pandas DataFrame转换为数组(或列表),才能表明存在其他问题。我强烈建议确保一个数据帧是您的特定用例合适的数据结构,而熊猫不包括执行你感兴趣的操作的任何方式。
AMC

Answers:


390

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

df.values

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

237

弃用的用法valuesas_matrix()

pandas v0.24.0引入了两种从pandas对象获取NumPy数组的新方法:

  1. to_numpy(),其定义上IndexSeries,DataFrame对象,并
  2. array,仅在IndexSeries对象上定义。

如果您访问的v0.24文档.values,则会看到一个红色的大警告:

警告:我们建议DataFrame.to_numpy()改为使用。

请参阅v0.24.0发行说明的本部分以及此答案以获取更多信息。


追求更好的一致性: to_numpy()

本着整个API更好的一致性的精神,to_numpy引入了一种新方法来从DataFrames中提取底层的NumPy数组。

# Setup.
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}, index=['a', 'b', 'c'])

df.to_numpy()
array([[1, 4],
       [2, 5],
       [3, 6]])

如上所述,该方法也在IndexSeries对象上定义(请参见此处)。

df.index.to_numpy()
# array(['a', 'b', 'c'], dtype=object)

df['A'].to_numpy()
#  array([1, 2, 3])

默认情况下,将返回视图,因此所做的任何修改都会影响原始视图。

v = df.to_numpy()
v[0, 0] = -1

df
   A  B
a -1  4
b  2  5
c  3  6

如果您需要副本,请使用to_numpy(copy=True

Pandas> = 1.0更新为ExtensionTypes

如果您使用的是熊猫1.x,那么您可能会更多地处理扩展类型。您必须多加注意,这些扩展名类型已正确转换。

a = pd.array([1, 2, None], dtype="Int64")                                  
a                                                                          

<IntegerArray>
[1, 2, <NA>]
Length: 3, dtype: Int64 

# Wrong
a.to_numpy()                                                               
# array([1, 2, <NA>], dtype=object)  # yuck, objects

# Right
a.to_numpy(dtype='float', na_value=np.nan)                                 
# array([ 1.,  2., nan])

在文档中对此进行了标注

如果您需要dtypes...

如另一个答案所示,DataFrame.to_records是执行此操作的好方法。

df.to_records()
# rec.array([('a', -1, 4), ('b',  2, 5), ('c',  3, 6)],
#           dtype=[('index', 'O'), ('A', '<i8'), ('B', '<i8')])

to_numpy不幸的是,这不能做到。但是,您也可以使用np.rec.fromrecords

v = df.reset_index()
np.rec.fromrecords(v, names=v.columns.tolist())
# rec.array([('a', -1, 4), ('b',  2, 5), ('c',  3, 6)],
#          dtype=[('index', '<U1'), ('A', '<i8'), ('B', '<i8')])

在性能方面,它几乎是相同的(实际上,使用rec.fromrecords速度要快一些)。

df2 = pd.concat([df] * 10000)

%timeit df2.to_records()
%%timeit
v = df2.reset_index()
np.rec.fromrecords(v, names=v.columns.tolist())

11.1 ms ± 557 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9.67 ms ± 126 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

添加新方法的理由

to_numpy()(除了array)作为两个GitHub问题GH19954GH23623下讨论的结果而添加

具体来说,文档提到了基本原理:

[...] .values尚不清楚返回的值是实际数组,它的某种转换还是熊猫自定义数组之一(如Categorical)。例如,使用PeriodIndex,每次都会.values 生成一个新ndarray的周期对象。[...]

to_numpy旨在提高API的一致性,这是朝正确方向迈出的重要一步。.values不会在当前版本中被弃用,但我希望这种情况可能会在将来的某个时刻发生,因此,我敦促用户尽快向较新的API迁移。


批判其他解决方案

DataFrame.values 如前所述,具有不一致的行为。

DataFrame.get_values()只是一个包装器DataFrame.values,因此上述所有内容均适用。

DataFrame.as_matrix()现在已弃用,请勿使用!


我不明白as_matrix在这种情况to_numpy下如何一页接一页地尖叫着人们尖叫着从肺部切换到另一种解决方案,而不解释如何恢复列选择功能as_matrix!我确定还有其他选择列的方法,但as_matrix至少是其中一种!
杰里米

@Jérémie除了显而易见的以外df[[col1, col2']].to_numpy()?不知道为什么您认为要宣传已淘汰功能的更新替代方案会否定答案。
cs95,19年

如果某些列属于列表类型,该怎么办。我如何才能以此创建平坦的凹凸阵列?
莫尼巴

@Moniba,您可能想根据需要首先将列表项目分解为单独的列/行。
cs95

除非我错了,否则在同一个调用中获得不止一列会将所有数据合并到一个大数组中。我想念什么吗?
安德里亚·莫罗

128

注意.as_matrix()不建议使用此答案中的方法。熊猫0.23.4警告:

方法.as_matrix将在以后的版本中删除。请改用.values。


熊猫内置一些东西...

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

30
这没有给出结构化的数组,所有列都是dtype object
sebix 2014年

14
“自版本0.23.0起不推荐使用:改用DataFrame.values。/“提供此方法是为了向后兼容。通常,建议使用'.values'。- github.com/pandas-dev/pandas/blob/...
大卫J.

4
现在已弃用。从v0.24开始,请to_numpy改用(.values两者都不选)。这里更多。
cs95,19年

1
“ FutureWarning:将来的版本中将删除方法.as_matrix。请改用.values。”
法哈德·马勒基

66

我只需要链接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')])

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

32

您可以使用该to_records方法,但是如果dtypes不是您一开始就想要的,就必须多花点时间。就我而言,从字符串复制了DF,索引类型为字符串(以objectdtypes在pandas中表示):

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(请参阅本期)。


2
要获得抢手的结构化数组(其性能比RecArray更好),您只需将RecArray传递给np.array构造函数即可。
流星2012年

我们只是修复了设置上面显示的索引名称的问题。
Chang She

26

似乎df.to_records()会为您工作。您正在寻找的确切功能已被要求to_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。您可以通过将其构造函数调用为,将结果移入常规numpy数组np.array(df.to_records())


3
等等,这个答案与to_records()5年前提到的@meteore的其他答案相比又增加了什么?
JohnE '18

13

尝试这个:

a = numpy.asarray(df)

嗨!请在回答中添加一些解释。目前,由于篇幅内容的原因,目前正在将其标记为低质量,并且有被系统删除的风险。谢谢!
d_kennetz

1
基本上将输入转换为数组(顾名思义)。因此,连同问题的上下文一起,该答案是有效的。检查docs.scipy.org/doc/numpy/reference/generated/...
劳塔罗帕拉达Opazo

谢谢,我认为这是不言而喻的。
大度汗

8

这是我从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.感谢约瑟夫·加尔文宁静 为他们的意见和解决方案。


不适用于我,错误:TypeError:无法理解数据类型
Joseph Garvin

感谢您的评论,并感谢cycyon的更正。我更新了答案,希望现在对您有用。
菲尔(Phil)2013年


5

示例DataFrame的更简单方法:

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

4

从数据框导出到arcgis表时遇到了类似的问题,偶然发现了来自usgs的解决方案(https://my.usgs.gov/confluence/display/cdi/pandas.DataFrame+to+ArcGIS+Table)。简而言之,您的问题具有类似的解决方案:

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

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

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

4

我经历了以上答案。“ as_matrix() ”方法可以使用,但是现在已经过时了。对我来说,有效的是“ .to_numpy() ”。

这将返回一个多维数组。如果您要从excel工作表中读取数据,并且需要从任何索引访问数据,则我会更喜欢使用此方法。希望这可以帮助 :)


您的意思是什么,您需要从任何索引访问数据?根据数据的性质,Pandas DataFrame甚至可能不是一开始的正确选择。
AMC

2

除了陨石的答案,我找到了代码

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

1

将数据帧转换为numpy数组的简单方法:

import pandas as pd
df = pd.DataFrame({"A": [1, 2], "B": [3, 4]})
df_to_array = df.to_numpy()
array([[1, 3],
   [2, 4]])

鼓励使用to_numpy来保持一致性。

参考:https : //pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_numpy.html


Arsam提供的解决方案与您的解决方案有什么区别?
qaiser

我只是想通过一个代码示例使其更加完整和可用,这是我个人所喜欢的。
user1460675 '19

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.