从熊猫数据框中填充numpy 3D矩阵

时间:2017-12-02 17:34:56

标签: python pandas numpy

我有一个包含以下列的数据框:

'价值'| 'x'| 'y'| 'z'|

x,y,z是整数,值是浮点数。

我想使用数据框中的值填充具有给定形状(与x,y和z的范围兼容)的numpy 3D矩阵 mat 。当坐标指向 mat 中的相同位置时,我只想添加值。

我可以使用for循环“手动”执行此操作但是有没有办法使用pandas / numpy函数执行此操作?

例如:

mat[0,0,0] = -2
mat[0,1,2] = 8.6

应该使用以下值导致 mat

SELECT user_id, MAX(session_date) as date_session, value FROM user_extra GROUP BY user_id

4 个答案:

答案 0 :(得分:2)

我可能会这样做:

In [185]: target = np.zeros(df.iloc[:, 1:].max() + 1)

In [186]: np.add.at(target, df.iloc[:, 1:].T.values.tolist(), df["value"])

In [187]: target
Out[187]: 
array([[[-2. ,  0. ,  0. ],
        [ 0. ,  0. ,  8.6]]])

In [188]: target.shape
Out[188]: (1, 2, 3)

In [189]: target[0, 0, 0]
Out[189]: -2.0

In [190]: target[0, 1, 2]
Out[190]: 8.5999999999999996

从值中构建适当大小的目标,然后使用np.add.at添加到目标并相应地处理重复项。唯一棘手的一点是我们需要转置(将X坐标放在一起等)并制作一个列表,以便正确解释索引。

答案 1 :(得分:1)

我看到至少有两个基于NumPy的。其中一个是np.add.at,已在@DSM's post中讨论,另一个在np.bincount中讨论过。使用np.bincount的实现看起来像这样 -

def dataframe_to_array(df, out_shp):
    ids = np.ravel_multi_index(df[['x','y','z']].values.T, out_shp)
    val = df['value'].values
    return np.bincount(ids, val, minlength=np.prod(out_shp)).reshape(out_shp)

示例运行 -

In [115]: df
Out[115]: 
   value  x  y  z
0    5.6  0  1  2
1   -2.0  0  0  0
2    3.0  0  1  2

In [116]: out = dataframe_to_array(df, (3,3,3))

In [117]: out[0,0,0]
Out[117]: -2.0

In [118]: out[0,1,2]
Out[118]: 8.5999999999999996

基准

np.add.at基于@ DSM的解决方案 -

def dataframe_to_array_addat(df, out_shp):
    target = np.zeros(out_shp)
    np.add.at(target, df[['x','y','z']].T.values.tolist(), df["value"])
    return target

计时 -

In [182]: N = 200 # dataset size/array shape decider

In [183]: df = pd.DataFrame(np.random.randint(0,N,(100000,3)), 
                                     columns=[['x','y','z']])

In [184]: df['value'] = np.random.rand(df.shape[0])

In [185]: %timeit dataframe_to_array_addat(df, (N,N,N))
10 loops, best of 3: 36.1 ms per loop

In [186]: %timeit dataframe_to_array(df, (N,N,N))
100 loops, best of 3: 8.22 ms per loop

答案 2 :(得分:0)

听起来你需要多索引

df1=df.set_index(['x','y','z'])
df1.loc[(0,1,2)].sum()

Out[273]: 
value    8.6

答案 3 :(得分:0)

您可以像大熊猫loc_indexer

一样获取它
df=pd.DataFrame({'value': {0: 5.6, 1: -2.0, 2: 3.0},
 'x': {0: 0, 1: 0, 2: 0},
 'y': {0: 1, 1: 0, 2: 1},
 'z': {0: 2, 1: 0, 2: 2}})
fields = list('xyz') 

mat = df.groupby(fields).sum().loc

In [9]: mat[0,0,0]
Out[9]: 
value   -2.0
Name: (0, 0, 0), dtype: float64

In [10]: mat[0,1,2]
Out[10]: 
value    8.6
Name: (0, 1, 2), dtype: float64

或构建真正的矩阵:

mat2=np.full(df[fields].max()+1,np.nan)
for (x,y,z),v in mat.obj.iterrows(): mat2[x,y,z]=v