【问题标题】:Convert pandas dataframe to NumPy array将 pandas 数据框转换为 NumPy 数组
【发布时间】:2012-11-02 00:57:33
【问题描述】:

我有兴趣了解如何将 pandas 数据帧转换为 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]])

我该怎么做?


作为奖励,是否可以像这样保留数据类型?

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

或类似的?

【问题讨论】:

  • 为什么需要这个?无论如何,数据帧不是基于 numpy 数组吗?您应该能够在需要 numpy 数组的地方使用数据框。这就是为什么您可以将数据帧与 scikit-learn 一起使用,其中函数要求 numpy 数组。
  • 这里有几个可能与 dtypes 和 recarrays(又名记录数组或结构化数组)相关的链接:(1) stackoverflow.com/questions/9949427/… (2) stackoverflow.com/questions/52579601/…
  • 注意: 必须像这样将 Pandas DataFrame 转换为数组(或列表)可能表明存在其他问题。我强烈建议确保 DataFrame 是适合您的特定用例的数据结构,并且 Pandas 不包含任何执行您感兴趣的操作的方式。

标签: python arrays pandas numpy dataframe


【解决方案1】:

df.to_numpy()df.values 好,这就是原因。*

是时候弃用 valuesas_matrix() 了。

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

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

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

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

请参阅this section of the v0.24.0 release notesthis answer 了解更多信息。

* - to_numpy() 是我推荐的任何生产代码的方法,这些生产代码需要在未来的多个版本中可靠运行。但是,如果您只是在 jupyter 或终端中制作暂存器,则使用 .values 节省几毫秒的输入时间是一个允许的例外。您可以随时添加适合 n 完成。



实现更好的一致性:to_numpy()

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

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

# Convert the entire DataFrame
df.to_numpy()
# array([[1, 4, 7],
#        [2, 5, 8],
#        [3, 6, 9]])

# Convert specific columns
df[['A', 'C']].to_numpy()
# array([[1, 7],
#        [2, 8],
#        [3, 9]])

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

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  C
a -1  4  7
b  2  5  8
c  3  6  9

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


pandas >= ExtensionTypes 1.0 更新

如果您使用的是 pandas 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

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

# Also correct
a.to_numpy(dtype='int', na_value=-1)
# array([ 1,  2, -1])

这是called out in the docs


如果您需要结果中的dtypes...

如另一个答案所示,DataFrame.to_records 是一个很好的方法。

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

很遗憾,to_numpy 无法做到这一点。但是,作为替代方案,您可以使用np.rec.fromrecords

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

12.9 ms ± 511 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9.56 ms ± 291 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


添加新方法的理由

to_numpy()(除了array)是在GH19954GH23623 两个GitHub 问题下讨论的结果。

具体来说,文档提到了理由:

[...] with .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()?不知道为什么您认为想要宣传已弃用功能的更新替代方案需要对答案投反对票。
  • 如果某些列是列表类型。如何从中创建一个平坦的凹凸数组?
  • @Moniba 您可能希望首先根据您的要求将列表项分解为单独的列/行。
  • 除非我错了,否则在同一个调用中获取多于一列会将所有数据合并到一个大数组中。我错过了什么吗?
【解决方案2】:

要将 pandas 数据帧 (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]])

【讨论】:

  • 这不再是推荐的方法了!
【解决方案3】:

注意:此答案中使用的 .as_matrix() 方法已弃用。 Pandas 0.23.4 警告:

方法.as_matrix 将在未来版本中删除。请改用 .values。


Pandas 内置了一些东西...

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

【讨论】:

  • 这没有给出结构化数组,所有列都是 dtype object
  • “自 0.23.0 版起已弃用:改用 DataFrame.values。” / "提供此方法是为了向后兼容,一般建议使用‘.values’。” - github.com/pandas-dev/pandas/blob/…
  • 现在已弃用。从 v0.24 开始,请改用to_numpy(也不要使用.values)。更多here.
  • "FutureWarning:方法 .as_matrix 将在未来的版本中被删除。改用 .values。"
【解决方案4】:

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

要获得 dtype,我们需要使用 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')])

【讨论】:

  • 这个答案中唯一缺少的是如何从数据框中构造 dtype 以便您可以编写通用函数
【解决方案5】:

您可以使用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)。

【讨论】:

  • 要获得广受欢迎的结构化数组(比recarray 具有更好的性能),您只需将recarray 传递给np.array 构造函数。
  • 我们刚刚修复了设置上面显示的索引名称。
【解决方案6】:

看来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 数组中。

【讨论】:

  • 等等,与@meteore 5 年前提到to_records() 的其他答案相比,这个答案增加了什么?
【解决方案7】:

试试这个:

a = numpy.asarray(df)

【讨论】:

  • 嗨!请为您的答案添加一些解释。目前,由于 lengthcontent 的原因,它目前被审核标记为低质量,并且有被系统删除的风险。谢谢!
  • 基本上将输入转换为数组(顾名思义)。因此,连同问题的上下文,这个答案是有效的。检查docs.scipy.org/doc/numpy/reference/generated/…
  • 谢谢,我认为这是不言自明的。
【解决方案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 以避免使用 python 3 调用 .encode() 时出错。感谢 Joseph Garvinhalcyon 的评论和解决方案。

【讨论】:

  • 对我不起作用,错误:TypeError:数据类型不理解
  • 感谢您的评论和halcyon 的更正。我更新了我的答案,希望它现在对你有用。
【解决方案9】:

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

【讨论】:

    【解决方案10】:

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

    • mah_np_array = df.as_matrix(columns=None)

    • mah_np_array = df.values

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

    【讨论】:

      【解决方案11】:

      我浏览了上面的答案。 “as_matrix()”方法有效,但现在已过时。对我来说,有效的是“.to_numpy()”。

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

      【讨论】:

      • 你说的是什么意思,你需要从任何索引访问数据?根据数据的性质,Pandas DataFrame 甚至可能一开始就不是正确的选择。
      【解决方案12】:

      刚从数据框导出到 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')]))
      

      【讨论】:

        【解决方案13】:

        将dataframe转换为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提供的解决方案和你的有什么区别...
        • 只是尝试通过一个代码示例使其更完整和可用,这是我个人更喜欢的。
        • 这个答案和第二个最受好评的答案有什么区别?
        【解决方案14】:

        试试这个:

        np.array(df) 
        
        array([['ID', nan, nan, nan],
           ['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=object)
        

        更多信息请访问:[https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html] 适用于 numpy 1.16.5 和 pandas 0.25.2。

        【讨论】:

          【解决方案15】:

          对流星的回答,我找到了代码

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

          【讨论】:

            猜你喜欢
            • 2020-06-20
            • 2022-01-12
            • 2014-03-23
            • 2017-06-28
            • 2016-03-31
            • 2019-02-25
            • 2021-07-21
            相关资源
            最近更新 更多