Python Pandas - 使用loc创建Fortran顺序的NumPy数组

3

例如:

nrow = 10
ncol= 10
a = np.arange(nrow*ncol,dtype=np.int32).reshape(nrow,ncol)
a = pd.DataFrame(a)
ix_list = np.arange(nrow,dtype=np.int32)

print np.isfortran(a.values) #  False
print np.isfortran(a.loc[ix_list,:].values) #  True

为什么使用 .loc 创建的 Pandas 数据帧是 Fortran 排序的 Numpy 数组?我能否强制它创建 C 排序的 Numpy 数组的 Pandas 数据帧?

这个 loc 产生的数组的 shape 是什么?它的 flags 是什么? - hpaulj
你的意思是从a.loc[ix_list,:]获取ndarray的形状吗?它与a具有相同的形状,而在这种情况下是(10,10)。 - Hansol Shin
2个回答

0
In [423]: adf = pd.DataFrame(a)
In [424]: ix_list = np.arange(nrow,dtype=np.int32)

您的问题是创建了一个 F 排序数组,如 flagsstrides 所示。这是在对普通的 numpy 数组进行 transpose 时所期望看到的。

    In [426]: adf.loc[ix_list].values.flags
    Out[426]: 
      C_CONTIGUOUS : False
      F_CONTIGUOUS : True
      OWNDATA : False
      WRITEABLE : True
      ALIGNED : True
      UPDATEIFCOPY : False
    In [427]: adf.loc[ix_list].values.strides
    Out[427]: (4, 40)

但是其他loc索引会产生一个 C 顺序的数组:

In [428]: adf.loc[:].values.flags
Out[428]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  ....
In [429]: adf.loc[ix_list[::2]].values.flags
Out[429]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  ...
In [430]: adf.loc[ix_list[:-2]].values.flags
Out[430]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  ...

看起来是 pandasloc 索引器中的一个错误。

我猜想 np.ascontiguousarray 是确保所有情况都是 C 排序的最便宜的方法,因为它执行了一个 np.array(..., copy=False),这是一个有条件的 copy。已经是 C 的数组不会复制。

在快速测试中,添加 copynp.ascontiguousarray 不会减慢速度。

In [439]: timeit np.ascontiguousarray(adf.loc[ix_list].values).flags
514 µs ± 7.07 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [440]: timeit adf.loc[ix_list].values.copy().flags
509 µs ± 5.94 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [441]: timeit adf.loc[ix_list].values.flags
513 µs ± 18.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [442]: timeit adf.loc[:].values.flags
24.9 µs ± 11.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [443]: timeit np.ascontiguousarray(adf.loc[:].values).flags
30 µs ± 865 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [444]: timeit adf.loc[ix_list[:-1]].values.flags
559 µs ± 12.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [445]: timeit np.ascontiguousarray(adf.loc[ix_list[:-1]].values).flags
559 µs ± 1.41 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

在numpy数组上选择行比使用loc要快得多:

In [446]: timeit adf.loc[:].values[ix_list].flags
32.9 µs ± 1.33 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [447]: timeit adf.values[ix_list].flags
20.9 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

0

我无法回答你的第一个问题,但是在你的数据框上调用 .values 会返回一个numpy ndarray,因此:

希望能有所帮助!


非常感谢。我一直在寻找强制 .loc 直接创建 C 有序 ndarray 以解决性能问题的方法。当与更大的 Fortran 有序 ndarray 一起使用时,np.ascontiguousarray()速度较慢。 - Hansol Shin
好的,你能分享一下你的发现吗? - David Leon
抱歉,我的意思是我找不到这样的方法。 - Hansol Shin
抱歉,我的错。以防万一,你考虑转置你的数组吗?例如使用a.loc[ix_list,:].transpose().values? - David Leon
另一个问题,为什么需要使用 .loc?你是否可以像这样只使用 df 选择:a[ix_list].values? - David Leon
感谢您的建议。a.loc[ix_list,:].transpose().values会返回C顺序的ndarray,但我需要从.loc获取ndarray,而不是转置。a[ix_list].values可以工作,但是a[ix_list].values和a.loc[id_list:]通常会返回不同的pandas dataframe,因为a[ix_list]是选择列,而a.loc[id_list:]是选择索引。 - Hansol Shin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接