Python Numpy高效的切片连接

2024-04-20 08:44:53 发布

您现在位置:Python中文网/ 问答频道 /正文

提到我之前发布的一个问题:Efficient use of Numpy to process in blocks of rows

我和熊猫有一些很好的舵手(谢谢@jdehesa),但我真的需要和numpy一起工作。我主要关心的是如何将切片组合成一个,即:

dfconcat = np.concatenate((dfconcat, dfslice),axis=0)

这似乎是一种非常低效的组合切片的方法,我觉得这应该可以在循环之外的一个步骤中完成(可能通过向引用每个AccountID的dfslice数组添加另一个维度)?我的方法是正确的还是有更好的方法?迄今为止的工作:

import pandas as pd
df = pd.DataFrame({'AccountID': [1,1,1,2,1,2,1,2,2],
                   'RefDay':    [1,2,3,1,4,2,5,3,4],
                   'BCol':      [1,2,np.nan,1,3,2,1,np.nan,2],
                   'CCol':      [3,2,3,1,3,4,5,2,1]})
df = df[['AccountID','RefDay','BCol','CCol']] #sorting out order

df['TargetCol']=np.nan
dfnum = df.to_records(index=False)
dfnum = np.sort(dfnum, order=['AccountID','RefDay']) #make sure the order is correct

uniquelist = np.unique(dfnum['AccountID'])
for u in range(0,len(uniquelist)):
    dfslice = dfnum[dfnum['AccountID'] == uniquelist[u]]
    for i in range(0,len(dfslice)):
        if (len(dfslice) - i) >= 3:
            dfslice['TargetCol'][i] = np.nansum(dfslice['BCol'][i:i+3]) / dfslice['CCol'][i]
        else:
            dfslice['TargetCol'][i] = np.NaN
    if u==0:
        dfconcat = dfslice
    else:
        dfconcat = np.concatenate((dfconcat, dfslice),axis=0)

pd.DataFrame(dfconcat)

输出:

AccountID   RefDay  BCol    CCol    TargetCol
1           1       1.0     3       1.000000
1           2       2.0     2       2.500000
1           3       NaN     3       1.333333
1           4       3.0     3       NaN
1           5       1.0     5       NaN
2           1       1.0     1       3.000000
2           2       2.0     4       1.000000
2           3       NaN     2       NaN
2           4       2.0     1       NaN

Tags: 方法indfnpnanpdccolbcol
2条回答

免责声明:我对熊猫没有任何经验。你知道吗

首先,我认为通过添加额外的轴,你肯定是在正确的轨道上。你知道吗

您可以尝试提前创建数组,这样就不必调整数组的大小。初始化最后一个数组(我们称它为myarray,因为dfconcat马上就会引起误解)为一个DataFrames数组(如果im正确并且它基本上只是一个np.N阵列),长度为len(唯一列表)。这将防止发生多次调整大小的情况,这可能会导致将其复制到具有足够连续内存的位置。我认为这是你能取得的最大的胜利。你知道吗

在执行此操作时,您将不使用concatenate,而是可以指定:myarray[u]=dfslice,因为您知道元素的数目是正确的。或者直接写入最终数组,跳过dfslice构造

编辑:代码被删除,因为它不正确,因为数组太短。但是,我不知道你的代码在哪里得到了补偿。如果这让我的回答有点不清楚,我深表歉意。重要部分:
1) 抓住附加轴
2) 在填充数组之前,先创建完全大小的数组。你知道吗

首先是关于concatenate的问题,在列表中收集值更有效,例如alist.append(...)。最后创建一次数组。循环中重复的串联速度较慢。你知道吗


如果不使用Pandas,我认为您的dfnum数组可以构造为

In [162]: adict={'AccountID': [1,1,1,2,1,2,1,2,2],
     ...:                    'RefDay':    [1,2,3,1,4,2,5,3,4],
     ...:                    'BCol':      [1,2,np.nan,1,3,2,1,np.nan,2],
     ...:                    'CCol':      [3,2,3,1,3,4,5,2,1]}
     ...:                    
In [163]: 
In [163]: len(adict['CCol'])
Out[163]: 9

In [166]: arr = np.zeros(9, [('AccountID',int),('RefDay',int),('BCol',float),('CCol',int)])
In [167]: for n in arr.dtype.names:
     ...:     arr[n] = adict[n]
     ...:     
In [168]: arr
Out[168]: 
array([(1, 1,  1., 3), (1, 2,  2., 2), (1, 3, nan, 3), (2, 1,  1., 1),
       (1, 4,  3., 3), (2, 2,  2., 4), (1, 5,  1., 5), (2, 3, nan, 2),
       (2, 4,  2., 1)],
      dtype=[('AccountID', '<i8'), ('RefDay', '<i8'), ('BCol', '<f8'), ('CCol', '<i8')])

In [171]: dfnum = np.sort(arr, order=['AccountID','RefDay'])
In [174]: np.unique(dfnum['AccountID'], return_index=True, return_inverse=True)
Out[174]: (array([1, 2]), array([0, 5]), array([0, 0, 0, 0, 0, 1, 1, 1, 1]))

这是你的循环没有列表附加。你知道吗

In [182]: alist =[]; targets=[]
     ...: for u in range(0,len(uniquelist)):
     ...:     dfslice = dfnum[dfnum['AccountID'] == uniquelist[u]]
     ...:     target = np.zeros(len(dfslice))
     ...:     for i in range(0,len(dfslice)):
     ...:         if (len(dfslice) - i) >= 3:
     ...:             target[i] = np.nansum(dfslice['BCol'][i:i+3]) / dfslice['C
     ...: Col'][i]
     ...:         else:
     ...:             target[i] = np.NaN
     ...:     alist.append(dfslice)
     ...:     targets.append(target)
     ...:     
     ...:     
In [183]: alist
Out[183]: 
[array([(1, 1,  1., 3), (1, 2,  2., 2), (1, 3, nan, 3), (1, 4,  3., 3),
        (1, 5,  1., 5)],
       dtype=[('AccountID', '<i8'), ('RefDay', '<i8'), ('BCol', '<f8'), ('CCol', '<i8')]),
 array([(2, 1,  1., 1), (2, 2,  2., 4), (2, 3, nan, 2), (2, 4,  2., 1)],
       dtype=[('AccountID', '<i8'), ('RefDay', '<i8'), ('BCol', '<f8'), ('CCol', '<i8')])]
In [184]: targets
Out[184]: 
[array([1.        , 2.5       , 1.33333333,        nan,        nan]),
 array([ 3.,  1., nan, nan])]

我错过了TargetCol字段的添加,所以不得不用target进行篡改。你知道吗

In [185]: np.concatenate(alist)
Out[185]: 
array([(1, 1,  1., 3), (1, 2,  2., 2), (1, 3, nan, 3), (1, 4,  3., 3),
       (1, 5,  1., 5), (2, 1,  1., 1), (2, 2,  2., 4), (2, 3, nan, 2),
       (2, 4,  2., 1)],
      dtype=[('AccountID', '<i8'), ('RefDay', '<i8'), ('BCol', '<f8'), ('CCol', '<i8')])
In [186]: np.concatenate(targets)
Out[186]: 
array([1.        , 2.5       , 1.33333333,        nan,        nan,
       3.        , 1.        ,        nan,        nan])

我原以为有了Out[174]的附加输出,我就可以不用循环了,但我还没有弄清楚细节。你知道吗

相关问题 更多 >