【问题标题】:Access segment of row with correct dtype访问具有正确 dtype 的行段
【发布时间】:2021-09-25 17:31:30
【问题描述】:

我有一个包含几种不同类型的数据框。例如:

df = pd.DataFrame({'A': ['A', 'B', 'C', 'D'],
                   'B': np.random.randint(10, size=4),
                   'C': np.random.randint(10, size=4),
                   'D': np.random.rand(4),
                   'E': np.random.rand(4)})

数据类型是

>>> df.dtypes
A     object
B      int32
C      int32
D    float64
E    float64
dtype: object

我希望能够直接从df 的第三行中提取 dtype np.int32 的 numpy 数组中的 BC 的值。看起来很简单:

>>> df.iloc[2][['B', 'C']].to_numpy()
array([9, 9], dtype=object)

这与Series是object类型的事实一致:

>>> df.iloc[2]
A           C
B           9
C           9
D    0.211487
E    0.857848
Name: 2, dtype: object

所以也许我不应该先获得该行:

>>> df.loc[df.index[2], ['B', 'C']].to_numpy()
array([9, 9], dtype=object)

仍然没有运气。当然,我总是可以后期处理并做

df.loc[df.index[2], ['B', 'C']].to_numpy().astype(np.int32)

但是,有没有一种方法可以仅使用索引将一组具有相同 dtype 的列与其本机 dtype 提取到一个 numpy 数组中?

【问题讨论】:

  • 我从没想过这个问题,因为我已经习惯了索引链接(你的 V1 答案)。 V2 对我来说是新的。
  • @MichaelSzczesny。我机器上的新版 Spyder 有一些不错的自动完成功能。不能说我真的为那个做了研究。问题是我一开始的方向错了。
  • 我想这与 numpy 如何将 dtypes 存储在数组中的事实有关,如果我们使用 iloc 并使用索引而不是系列获取数据帧,我们会看到预期的行为,因为使用熊猫:df.iloc[[2],df.columns.get_indexer(['B','C'])].dtypes
  • @anky。基本上,一个系列是一个单一的数组,所以必须支持通用数据类型。您可能不需要索引器,序列 [2] 是它成为 df 的原因。
  • @anky。我误读了。前几次不明白索引器是什么。我的错。

标签: python pandas numpy dtype


【解决方案1】:

V1

答案当然与iloc相反:首先提取具有一致dtype的列,以便该行可以是一个连续的块:

>>> df[['B', 'C']].iloc[2]
array([9, 9])

这告诉我,我不应该直接使用 pandas,除非一开始就加载我的数据。

V2

原来pd.DataFrame.to_numpypd.Series.to_numpy 有一个dtype 参数,您可以使用它来进行转换。这意味着loc/iloc 方法也可以工作,尽管这仍然需要额外的转换和 dtype 的先验知识:

>>> df.loc[d.index[2], ['B', 'C']].to_numpy(dtype=np.int32)
array([9, 9])

>>> df.iloc[2][['B', 'C']].to_numpy(dtype=np.int32)
array([9, 9])

【讨论】:

  • 我添加了一些 ._mgr 显示以进一步说明您的答案。
  • @hpaulj。这很有趣。我有一个心智模型,这就是 pandas 的做法,但从来没有新的任何细节。我喜欢解决我从来不知道自己遇到的问题
【解决方案2】:

作为疯子回答的补充

In [107]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   A       4 non-null      object 
 1   B       4 non-null      int64  
 2   C       4 non-null      int64  
 3   D       4 non-null      float64
 4   E       4 non-null      float64
dtypes: float64(2), int64(2), object(1)
memory usage: 288.0+ bytes

我偶然发现了_mgr,它显然管理着数据的实际存储方式。看起来它试图将类似 dtype 的列组合在一起,将数据存储为 asn (#col, #row) 数组:

In [108]: df._mgr
Out[108]: 
BlockManager
Items: Index(['A', 'B', 'C', 'D', 'E'], dtype='object')
Axis 1: RangeIndex(start=0, stop=4, step=1)
FloatBlock: slice(3, 5, 1), 2 x 4, dtype: float64
IntBlock: slice(1, 3, 1), 2 x 4, dtype: int64
ObjectBlock: slice(0, 1, 1), 1 x 4, dtype: object

选择 2 个 int 列:

In [109]: df[['B','C']]._mgr
Out[109]: 
BlockManager
Items: Index(['B', 'C'], dtype='object')
Axis 1: RangeIndex(start=0, stop=4, step=1)
IntBlock: slice(0, 2, 1), 2 x 4, dtype: int64

因此我们int dtype 数组没有进一步的参数:

In [110]: df[['B','C']].values
Out[110]: 
array([[5, 0],
       [5, 0],
       [0, 5],
       [9, 9]])

对于单块情况(例如所有 int 列),values 是(或至少可以是)帧数据的 view。但这里的情况似乎并非如此。

对于单行:

In [116]: df.iloc[2]._mgr
Out[116]: 
SingleBlockManager
Items: Index(['A', 'B', 'C', 'D', 'E'], dtype='object')
ObjectBlock: 5 dtype: object

行选择是Series,所以不能有数据框的混合dtypes。

但是“多行”选择是一个框架

In [128]: df.iloc[2][['B','C']].values
Out[128]: array([0, 5], dtype=object)
In [129]: df.iloc[[2]][['B','C']].values
Out[129]: array([[0, 5]])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 2016-07-25
    • 2021-04-02
    • 2018-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多