Numpy:从熊猫数据帧创建可变长度序列

Posted

技术标签:

【中文标题】Numpy:从熊猫数据帧创建可变长度序列【英文标题】:Numpy: Creation of a variable length sequence from a pandas data-frame 【发布时间】:2019-06-05 09:38:20 【问题描述】:

假设我有以下数据框:

df_raw = pd.DataFrame("person_id": [101, 101, 102, 102, 102, 103], "date": [0, 5, 0, 7, 11, 0], "val1": [99, 11, 22, 33, 44, 22], "val2": [77, 88, 22, 66, 55, 33])

我想要实现的是创建一个 3 维 numpy 数组,结果应该如下:

np_pros = np.array([[[0, 99, 77], [5, 11, 88]], [[0, 22, 22], [7, 33, 66], [11, 44, 55]], [[0, 22, 33]]])

换句话说,3D 数组应具有以下形状[unique_ids, None, feature_size]。在我的例子中,unique_ids 的数量为 3,feature size 为 3(除person_id 之外的所有列),y 列的长度可变,它表示@987654328 的测量次数@。

我很清楚我可以创建一个np.zeros((unique_ids, max_num_features, feature_size)) 数组,填充它,然后删除我不需要但我想要更快的元素。原因是我的实际数据框很大(大约 [50000, 455]),这将导致一个大约 [12500, 200, 455] 的 numpy 数组。

期待您的回答!

【问题讨论】:

我不认为你可以创建一个这样的数组,每个内部数组都有不同的大小,组大小。但是,您可以有一个列表。 @DanielMesejo 那么你有什么建议?在内存和复杂性方面什么是最佳的? 之后你想做什么? 这是个好问题。获得序列后,我想使用 Tensorflow 执行分桶以动态填充序列。 这就是为什么我严格希望最终得到一个可变长度数组(之后在批处理中填充)。 【参考方案1】:

xarray 的另一个解决方案


让我们创建person_id 的重复性所隐含的维度
>>> df['newdim'] = df.person_id.duplicated()
>>> df.newdim    = df.groupby('person_id').newdim.cumsum()
>>> df           = df.set_index(["newdim", "person_id"])
>>> df
                  date  val1  val2
newdim person_id                  
0.0    101           0    99    77
1.0    101           5    11    88
0.0    102           0    22    22
1.0    102           7    33    66
2.0    102          11    44    55
0.0    103           0    22    33

为了可读性,我们可能想把df 变成xarray.Dataset-object

>>> xa = df.to_xarray()
>>> xa
<xarray.Dataset>
Dimensions:    (newdim: 3, person_id: 3)
Coordinates:
  * newdim     (newdim) float64 0.0 1.0 2.0
  * person_id  (person_id) int64 101 102 103
Data variables:
    date       (newdim, person_id) float64 0.0 0.0 0.0 5.0 7.0 nan nan 11.0 nan
    val1       (newdim, person_id) float64 99.0 22.0 22.0 11.0 33.0 nan nan ...
    val2       (newdim, person_id) float64 77.0 22.0 33.0 88.0 66.0 nan nan ...

然后进入一个维度健康 numpy 数组

>>> ar = xa.to_array().T.values
>>> ar
array([[[ 0., 99., 77.],
        [ 5., 11., 88.],
        [nan, nan, nan]],

       [[ 0., 22., 22.],
        [ 7., 33., 66.],
        [11., 44., 55.]],

       [[ 0., 22., 33.],
        [nan, nan, nan],
        [nan, nan, nan]]])

请注意,nan-values 是通过强制引入的。

【讨论】:

【参考方案2】:

这是一种方法:

ix = np.flatnonzero(df1.person_id != df1.person_id.shift(1))
np.split(df1.drop('person_id', axis=1).values, ix[1:])

[array([[ 0, 99, 77],
        [ 5, 11, 88]], dtype=int64), 
 array([[ 0, 22, 22],
        [ 7, 33, 66],
        [11, 44, 55]], dtype=int64), 
 array([[ 0, 22, 33]], dtype=int64)]

详情

在将df1 与自身的移位版本 (pd.shift) 进行比较后使用np.flatnonzero,以获得person_id 发生变化的索引:

ix = np.flatnonzero(df1.person_id != df1.person_id.shift(1))
#array([0, 2, 5])

使用np.split 以便根据获得的索引拆分数据框的感兴趣列:

np.split(df1.drop('person_id', axis=1).values, ix[1:])

[array([[ 0, 99, 77],
        [ 5, 11, 88]], dtype=int64), 
 array([[ 0, 22, 22],
        [ 7, 33, 66],
        [11, 44, 55]], dtype=int64), 
 array([[ 0, 22, 33]], dtype=int64)]

【讨论】:

【参考方案3】:

你可以使用groupby:

import pandas as pd

df_raw = pd.DataFrame("person_id": [101, 101, 102, 102, 102, 103], "date": [0, 5, 0, 7, 11, 0], "val1": [99, 11, 22, 33, 44, 22], "val2": [77, 88, 22, 66, 55, 33])

result = [group.values for _, group in df_raw.groupby('person_id')[['date', 'val1', 'val2']]]
print(result)

输出

[array([[  0, 101,  99,  77],
       [  5, 101,  11,  88]]), array([[  0, 102,  22,  22],
       [  7, 102,  33,  66],
       [ 11, 102,  44,  55]]), array([[  0, 103,  22,  33]])]

【讨论】:

以上是关于Numpy:从熊猫数据帧创建可变长度序列的主要内容,如果未能解决你的问题,请参考以下文章

在熊猫中将可变长度列表保存到 HDF5

熊猫滚动适用于可变窗口长度

从具有可变长度的列表字典创建数据框

ggplot2使用单独的日期和可变数据帧按日期绘制时间序列r

scala数据结构与可变不可变

pytorch对可变长度序列的处理