2017-05-30 48 views
3

動機

我經常回答一些問題,我主張將數據幀值轉換爲底層numpy數組以便快速計算。但是,這樣做有一些注意事項,並且有些方法比其他方式更好。如何從數據框中爲列的子集高效地獲取numpy數組?

我會提供自己的答案,努力回饋社區。我希望你們覺得它有用。

問題
考慮數據框df

df = pd.DataFrame(dict(A=[1, 2, 3], B=list('xyz'), C=[9, 8, 7], D=[4, 5, 6])) 
print(df) 

    A B C D 
0 1 x 9 4 
1 2 y 8 5 
2 3 z 7 6 

dtypes

print(df.dtypes) 

A  int64 
B object 
C  int64 
D  int64 
dtype: object 

我想創建一個numpy的陣列a是由來自列AC的價值觀。假設可能有許多列和我瞄準的兩個特定的列AC

我已經試過

我可以這樣做:

df[['A', 'C']].values 

array([[1, 9], 
     [2, 8], 
     [3, 7]]) 

這是正確的!

不過,我可以用numpy的

p = [df.columns.get_loc(i) for i in ['A', 'C']] 
df.values[:, p] 

array([[1, 9], 
     [2, 8], 
     [3, 7]], dtype=object) 

這是更快,但不準確的做到這一點更快。請注意0​​。我需要整數!

p = [df.columns.get_loc(i) for i in ['A', 'C']] 
df.values[:, p].astype(int) 

array([[1, 9], 
     [2, 8], 
     [3, 7]]) 

這現在是正確的,但我可能不知道我有所有整數。

時序

# Clear and accurate, but slower 
%%timeit 
df[['A', 'C']].values 
1000 loops, best of 3: 347 µs per loop 

# Not accurate, but close and fast 
%%timeit 
p = [df.columns.get_loc(i) for i in ['A', 'C']] 
df.values[:, p] 
10000 loops, best of 3: 59.2 µs per loop 

# Accurate for this test case and fast, needs to be more generalized. 
%%timeit 
p = [df.columns.get_loc(i) for i in ['A', 'C']] 
df.values[:, p].astype(int) 
10000 loops, best of 3: 59.3 µs per loop 

回答

4

pandas確實存儲在values屬性整個數據幀的單個陣列。在數據幀上調用values屬性時,它將從存儲的基礎對象(即pd.Series對象)構建陣列。將數據幀視爲pd.Seriespd.Series是有用的,其中每列是數據幀包含的一個這樣的pd.Series。每列可以有一個不同於其餘的dtype。這是數據框如此有用的原因之一。但是,一個numpy數組必須有一個類型。當我們在數據幀上調用values屬性時,它將轉到每一列,並從各個values屬性中提取數據並將它們拼湊在一起。如果各個dtypes的列不一致,則生成的數組的dtype將被強制爲object

選項1個
緩慢而準確

a = df[['A', 'C']].values 

的原因,這是緩慢的,因爲你問大熊貓建立你一個新的數據幀df[['A', 'C']]然後去和打鬧建立數組a新數據框的列值屬性。

選項2
查找列位置然後切片values

c = ['A', 'C'] 
p = [df.columns.get_loc(i) for i in c] 
a = df.values[:, p].astype(df.dtypes[c[0]]) 

這是更好,因爲我們只建立值陣列無需重新構建一個新的數據幀。我相信我們正在獲得一個具有一致dtype的數組。如果需要上演,我在這裏處理得並不好。

選項3
我的首選方法
只有訪問我關心的列的值約

a = np.column_stack([df[col].values for col in ['A', 'C']]) 

這利用了大熊貓據幀作爲pd.Series的容器中,我訪問只有我關心的列的values屬性。然後我從這些數組中構建一個新的數組。如果需要解決施法問題,numpy會處理它。


所有方法產生相同的結果

array([[1, 9], 
     [2, 8], 
     [3, 7]]) 

定時
小數據

%%timeit 
a = df[['A', 'C']].values 
1000 loops, best of 3: 338 µs per loop 

%%timeit 
c = ['A', 'C'] 
p = [df.columns.get_loc(i) for i in c] 
a = df.values[:, p].astype(df.dtypes[c[0]]) 
10000 loops, best of 3: 166 µs per loop 

%timeit np.column_stack([df[col].values for col in ['A', 'C']]) 
The slowest run took 7.36 times longer than the fastest. This could mean that an intermediate result is being cached. 
100000 loops, best of 3: 8.97 µs per loop 

大數據

df = pd.concat(
    [df.join(pd.DataFrame(
       np.random.randint(10, size=(3, 22)), 
       columns=list(ascii_uppercase[4:]) 
      ))] * 10000, ignore_index=True 
) 


%%timeit 
a = df[['A', 'C']].values 
The slowest run took 23.28 times longer than the fastest. This could mean that an intermediate result is being cached. 
1000 loops, best of 3: 371 µs per loop 
In [305]: 

%%timeit 
c = ['A', 'C'] 
p = [df.columns.get_loc(i) for i in c] 
a = df.values[:, p].astype(df.dtypes[c[0]]) 
100 loops, best of 3: 9.62 ms per loop 

%timeit np.column_stack([df[col].values for col in ['A', 'C']]) 
The slowest run took 6.66 times longer than the fastest. This could mean that an intermediate result is being cached. 
10000 loops, best of 3: 55.6 µs per loop 
+0

pd系列是否使用numpy數組來存儲其值? – hpaulj

+0

非常有用!我需要爲此加書籤。 – Windchill

+0

@hpaulj我會說實話,我不能確定。但我很確定這是一個肯定的答案。 [**'@屬性; def values' **](https://github.com/pandas-dev/pandas/blob/42e2a87f2a8848795238de1259a3daa5612e393d/pandas/core/series.py#L351)引用了我無法追蹤的'_data'屬性。但是[**'def __init__' **](https://github.com/pandas-dev/pandas/blob/42e2a87f2a8848795238de1259a3daa5612e393d/pandas/core/series.py#L139)顯示'data'屬性被分配了一個[**'SingleBlockManager **](https://github.com/pandas-dev/pandas/blob/42e2a87f2a8848795238de1259a3daa5612e393d/pandas/core/internals.py#L4070) – piRSquared

1

試試這個:比最快的長

%%timeit 
np.array(zip(df['A'].values, df['C'].values)) 

最慢的跑了5.51倍:

np.array(zip(df['A'].values, df['C'].values)) 

timeit。這可能意味着正在緩存中間結果。 10000循環,最好的3:每循環17.8微秒

相關問題