簡體   English   中英

如何將稀疏的熊貓數據框轉換為二維Numpy數組

[英]How to transform a sparse pandas dataframe to a 2d numpy array

我有一個包含x,y列(均從0開始)和幾個value列的數據框df。 x和y坐標不完整,意味着許多xy組合,有時會丟失完整的x或y值。 我想創建一個具有形狀(df.x.max()+ 1,(df.y.max()+ 1))的完整矩陣的2-d numpy數組,並將缺少的值替換為np.nan。 pd.pivot已經很接近了,但是並不能完全填充丟失的x / y值。

下面的代碼已經實現了所需的功能,但是由於使用了for循環,因此速度很慢:

img = np.full((df.x.max() + 1, df.y.max() +1 ), np.nan)
col = 'value'
for ind, line in df.iterrows():
    img[line.x, line.y] = line[value]

一個明顯更快的版本如下:

ind = pd.MultiIndex.from_product((range(df.x.max() + 1), range(df.y.max() +1 )), names=['x', 'y'])
s_img = pd.Series([np.nan]*len(ind), index=ind, name='value')
temp = df.loc[readout].set_index(['x', 'y'])['value']
s_img.loc[temp.index] = temp
img = s_img.unstack().values

問題是是否存在矢量化方法,這可能會使代碼更短,更快。

感謝您提前提供任何提示!

通常,填充NumPy數組最快的方法是簡單地分配一個數組,然后使用向量化運算符或函數為其分配值。 在這種情況下, np.put似乎很理想,因為它允許您使用(平坦的)索引數組和值數組分配值。

nrows, ncols = df['x'].max() + 1, df['y'].max() +1
img = np.full((nrows, ncols), np.nan)
ind = df['x']*ncols + df['y']
np.put(img, ind, df['value'])

下面是一個基准測試,它顯示了使用np.put可以比alt (非unstack方法)快82倍來制作形狀為(100,100)的結果數組:

In [184]: df = make_df(100,100)

In [185]: %timeit orig(df)
161 ms ± 753 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [186]: %timeit alt(df)
31.2 ms ± 235 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [187]: %timeit using_put(df)
378 µs ± 1.56 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [188]: 31200/378
Out[188]: 82.53968253968254

這是用於基准測試的設置:

import numpy as np
import pandas as pd

def make_df(nrows, ncols):
    df = pd.DataFrame(np.arange(nrows*ncols).reshape(nrows, ncols))
    df.index.name = 'x'
    df.columns.name = 'y'
    ind_x = np.random.choice(np.arange(nrows), replace=False, size=nrows//2)
    ind_y = np.random.choice(np.arange(ncols), replace=False, size=ncols//2)
    df = df.drop(ind_x, axis=0).drop(ind_y, axis=1).stack().reset_index().rename(columns={0:'value'})
    return df

def orig(df):
    img = np.full((df.x.max() + 1, df.y.max() +1 ), np.nan)
    col = 'value'
    for ind, line in df.iterrows():
        img[line.x, line.y] = line['value']
    return img

def alt(df):
    ind = pd.MultiIndex.from_product((range(df.x.max() + 1), range(df.y.max() +1 )), names=['x', 'y'])
    s_img = pd.Series([np.nan]*len(ind), index=ind, name='value')
    # temp = df.loc[readout].set_index(['x', 'y'])['value']
    temp = df.set_index(['x', 'y'])['value']
    s_img.loc[temp.index] = temp
    img = s_img.unstack().values
    return img

def using_put(df):
    nrows, ncols = df['x'].max() + 1, df['y'].max() +1
    img = np.full((nrows, ncols), np.nan)
    ind = df['x']*ncols + df['y']
    np.put(img, ind, df['value'])
    return img

另外,由於您的DataFrame是稀疏的,因此您可能對創建稀疏矩陣感興趣:

import scipy.sparse as sparse

def using_coo(df):
    nrows, ncols = df['x'].max() + 1, df['y'].max() +1    
    result = sparse.coo_matrix(
        (df['value'], (df['x'], df['y'])), shape=(nrows, ncols), dtype='float64')
    return result

正如人們所期望的那樣,(從稀疏數據中)制作稀疏矩陣比創建密集NumPy數組更快(並且需要更少的內存):

In [237]: df = make_df(100,100)

In [238]: %timeit using_put(df)
381 µs ± 2.63 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [239]: %timeit using_coo(df)
196 µs ± 1.26 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [240]: 381/196
Out[240]: 1.9438775510204083

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM