将熊猫数据帧转换为NumPy数组

如何将熊猫数据帧转换为NumPy数组?

DataFrame:

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')])
1450838 次浏览

您可以使用to_records方法,但是如果dtype不是您想要的,那么就必须使用它们。在我的例子中,从一个字符串复制你的DF,索引类型是字符串(由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')])

转换重数组dtype不为我工作,但在熊猫已经可以这样做:

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(参见这个问题)。

我只需要链接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,我们需要使用视图将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')])

< em >注意:这个答案中使用的.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]])

下面是我从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数据帧中创建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()时出错。感谢约瑟夫·加文宁静的的评论和解决方案。

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

要将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]])
当从dataframe导出到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')]))

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

  • # EYZ0

  • # EYZ0

道格:# EYZ0

看起来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()),可以将结果移动到常规numpy数组中。

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

使用# EYZ0

它比df.values好,原因如下

现在是时候弃用valuesas_matrix()了。

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

  1. to_numpy(),它是在IndexSeriesDataFrame对象上定义的
  2. array,它只在IndexSeries对象上定义。

如果你访问.values的v0.24文档,你会看到一个红色的警告,上面写着:

警告:我们建议使用DataFrame.to_numpy()代替。

有关更多信息,请参阅v0.24.0版本的本节说明这个答案

* - 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对象上(参见在这里)。

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 >= 1.0更新的ExtensionTypes

如果你用的是熊猫。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])

这是在文档中被喊出来了


如果你需要结果中的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)是在两个GitHub问题GH19954GH23623下讨论的结果。

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

< p >[…]使用.values,不清楚返回值是否为 实际的阵列,它的一些变换,或熊猫的习俗之一 数组(如Categorical)。例如,使用PeriodIndex.values 每次生成一个新的周期对象ndarray。[…]< / p >

to_numpy旨在提高API的一致性,这是朝着正确方向迈出的重要一步。.values在当前版本中不会被弃用,但我预计在未来的某个时候会发生这种情况,所以我会敦促用户尽快迁移到更新的API。



其他解决方案的批评

正如前面提到的,DataFrame.values具有不一致的行为。

DataFrame.get_values()在1.0版悄然删除,之前在0.25版本中已弃用。在此之前,它只是DataFrame.values的包装,所以上面所说的一切都适用。

DataFrame.as_matrix()在v1.0中被移除,之前在v0.23中已弃用。使用 !

试试这个:

a = numpy.asarray(df)

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

这将返回一个多维数组。我更喜欢使用这种方法,如果你从excel表读取数据,你需要从任何索引访问数据。希望这对你有所帮助。

一个简单的方法将数据帧转换为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。

< p >参考: # EYZ0 < / p >

试试这个:

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