从数据帧的列切片中获取numpy值的最快方法是什么?

时间:2017-03-23 00:12:42

标签: python pandas numpy

我经常尝试决定如何将numpy数组与pandas数据框中的多个但不是所有列相关联。

所以我想问一下,获取与数据框中的几个但不是所有列关联的值数组的最有效方法是什么?

示例

df = pd.DataFrame(np.arange(10).reshape(-1, 5), columns=list('ABCDE'))
print(df)

   A  B  C  D  E
0  0  1  2  3  4
1  5  6  7  8  9

什么是最快的获取方式

df[['B', 'D']].values

array([[1, 3],
       [6, 8]])

2 个答案:

答案 0 :(得分:2)

我想到了这些方法......我更欢迎在分析中加​​入

<强> 结论
对于少量列,似乎找到列位置和使用整数切片非常有效。但是对于大型数组和大量列,as_matrix非常好(正如预期的那样)。

from timeit import timeit
import pandas as pd
import numpy as np
from string import ascii_uppercase as up


def slc_df_2val(df, cols):
    return df[cols].values

def as_matrix(df, cols):
    return df.as_matrix(cols)

def hstack_per_col(df, cols):
    return np.hstack([df[c].values[:, None] for c in cols])

def stack_per_col_T(df, cols):
    return np.stack([df[c].values for c in cols]).reshape(-1, len(cols))

def get_loc_slc_array(df, cols):
    a = [df.columns.get_loc(c) for c in cols]
    return df.values[:, a]

然后我进行以下测试

mcol = pd.MultiIndex.from_product([list(up[:10]), list(up[-10:])])

sizes = pd.MultiIndex.from_product(
    [[10, 100, 1000, 10000], [1, 5, 10, 20, 30, 40]],
    names=['n', 'm'])

methods = pd.Index(
    'slc_df_2val as_matrix hstack_per_col stack_per_col_T get_loc_slc_array'.split(),
    name='method')

results = pd.DataFrame(index=sizes, columns=methods)

np.random.seed([3,1415])
for n in sizes.levels[0]:
    df = pd.DataFrame(np.arange(n * 100).reshape(-1, 100), columns=mcol)
    for m in sizes.levels[1]:
        cols = np.random.choice(mcol, m, replace=False)
        for f in methods:
            stmt = '{}(df, cols)'.format(f)
            setup = 'from __main__ import {}, df, cols'.format(f)
            tvalue = timeit(stmt, setup, number=500)
            results.set_value((n, m), f, tvalue)

从每个方法发生的事情的角度绘制results,因为我们提取的列数增加。

fig, axes = plt.subplots(2, 2, figsize=(8, 6))
for i, n in enumerate(sizes.levels[0]):
    ax = axes[i // 2, i % 2]
    results.xs(n).plot(lw=2, ax=ax, title='size {}'.format(n))
    ax.legend().remove()

axes[-1, -1].legend(bbox_to_anchor=(1.7, 2.4), fontsize=10)

fig.suptitle('Num Columns Perspective', fontsize=10)

fig.tight_layout()
plt.subplots_adjust(top=.9)

enter image description here

然后从增长数组长度的角度来看

fig, axes = plt.subplots(3, 2, figsize=(8, 9))
for i, m in enumerate(sizes.levels[1]):
    ax = axes[i // 2, i % 2]
    results.xs(m, level=1).plot(lw=2, ax=ax, title='num cols {}'.format(m), rot=45)
    ax.legend().remove()

axes[-1, -1].legend(bbox_to_anchor=(1.7, 4.1), fontsize=10)

fig.suptitle('Array Length Perspective', fontsize=10)

fig.tight_layout()
plt.subplots_adjust(top=.9)

enter image description here

答案 1 :(得分:1)

这是通过使用np.searchsorted对应给定字符串索引获取列整数索引的方法 -

def linear_index(df, cols):    
    r,c = df.columns.levels
    d0 = np.array([i[0] for i in cols])
    d1 = np.array([i[1] for i in cols])    

    # Skip getting the argsorts if column names are already sorted
    r_sidx = r.argsort()
    c_sidx = c.argsort()

    return np.searchsorted(r,d0,sorter = r_sidx)*len(c) + \
                        np.searchsorted(c,d1, sorter=c_sidx)

def searchsorted_loc(df, cols):
    return df.values[:, linear_index(df, cols)]

这适用于multi-index数据框。使用一个级别的数据帧时,它会简化。