熊猫:从行的特定列中选择值

给定一个包含多列的DataFrame,我们如何从特定列中逐行选择值来创建新的Series?熊猫:从行的特定列中选择值

df = pd.DataFrame({"A":[1,2,3,4], 

"B":[10,20,30,40],

"C":[100,200,300,400]})

columns_to_select = ["B", "A", "A", "C"]

目标: [10, 2, 3, 400]

一个方法,工作原理是利用一个适用的语句。

df["cols"] = columns_to_select 

df.apply(lambda x: x[x.cols], axis=1)

不幸的是,这不是一个矢量化操作,需要很长时间处理大型数据集。任何想法,将不胜感激。

回答:

Pandas approach:

In [22]: df['new'] = df.lookup(df.index, columns_to_select) 

In [23]: df

Out[23]:

A B C new

0 1 10 100 10

1 2 20 200 2

2 3 30 300 3

3 4 40 400 400

回答:

NumPy的方式

下面是使用advanced indexing一个矢量NumPy的方式 -

# Extract array data 

In [10]: a = df.values

# Get integer based column IDs

In [11]: col_idx = np.searchsorted(df.columns, columns_to_select)

# Use NumPy's advanced indexing to extract relevant elem per row

In [12]: a[np.arange(len(col_idx)), col_idx]

Out[12]: array([ 10, 2, 3, 400])

如果df列名不排序,我们需要使用sorter大吵np.searchsorted。该代码提取col_idx,例如通用df是:

# https://stackoverflow.com/a/38489403/ @Divakar 

def column_index(df, query_cols):

cols = df.columns.values

sidx = np.argsort(cols)

return sidx[np.searchsorted(cols,query_cols,sorter=sidx)]

所以,col_idx会像这样获得 -

col_idx = column_index(df, columns_to_select) 

进一步优化

剖析它揭示了瓶颈正在处理字符串np.searchsorted,通常NumPy的弱点与字符串没有太大关系。所以,为了克服这个问题,并使用列名为单个字母的特殊情况,我们可以快速将它们转换为数字,然后将它们提供给searchsorted以加快处理速度。

因此,获得基于整数列ID,对于列名的单字母排序的情况的优化版本,将是 -

def column_index_singlechar_sorted(df, query_cols): 

c0 = np.fromstring(''.join(df.columns), dtype=np.uint8)

c1 = np.fromstring(''.join(query_cols), dtype=np.uint8)

return np.searchsorted(c0, c1)

这给了我们解决方案的修改版,像这样 -

计时 -

In [149]: # Setup df with 26 uppercase column letters and many rows 

...: import string

...: df = pd.DataFrame(np.random.randint(0,9,(1000000,26)))

...: s = list(string.uppercase[:df.shape[1]])

...: df.columns = s

...: idx = np.random.randint(0,df.shape[1],len(df))

...: columns_to_select = np.take(s, idx).tolist()

# With df.lookup from @MaxU's soln

In [150]: %timeit pd.Series(df.lookup(df.index, columns_to_select))

10 loops, best of 3: 76.7 ms per loop

# With proposed one from this soln

In [151]: %%timeit

...: a = df.values

...: col_idx = column_index_singlechar_sorted(df, columns_to_select)

...: out = pd.Series(a[np.arange(len(col_idx)), col_idx])

10 loops, best of 3: 59 ms per loop

鉴于df.lookup解决了一般情况,这可能是一个更好的选择,但其他可能的优化,如这篇文章中所示,也可以很方便!

以上是 熊猫:从行的特定列中选择值 的全部内容, 来源链接: utcz.com/qa/267128.html

回到顶部