在不使用for循环的不等行长度的numpy数组中获取所需元素

时间:2016-09-23 21:47:55

标签: python arrays pandas numpy

我有以下numpy数组:

array([['apple','banana','orange'],
   ['car','bike','train','ship','plane','scooter'],
   ['red','purple']], dtype=object)

数组中的各行长度不等,我想得到每行的最后一个元素。我可以通过运行for循环来获得这个,但我想可能有更直接的方法。我最接近(错误的解决方案)是arr [:] [ - 1]它给了我最后一行的元素和arr [np.arange(len(arr)), - 1]它会抛出'IndexError'错误。

我想要的输出是:

array([['orange','scooter','purple']], dtype=object)

我将不胜感激任何指导。谢谢。

3 个答案:

答案 0 :(得分:1)

使用熊猫:

In [87]: a
Out[87]: array([['apple', 'banana', 'orange'], ['car', 'bike', 'train', 'ship', 'plane', 'scooter'], ['red', 'purple']], dtype=object)

In [88]: df = pd.DataFrame(a)

In [93]: df
Out[93]:
                                          0
0                   [apple, banana, orange]
1  [car, bike, train, ship, plane, scooter]
2                             [red, purple]

In [94]: df[0].str[-1]
Out[94]:
0     orange
1    scooter
2     purple
Name: 0, dtype: object

或作为NumPy数组:

In [95]: df[0].str[-1].values
Out[95]: array(['orange', 'scooter', 'purple'], dtype=object)

答案 1 :(得分:1)

如果最快,请使用列表清单:

import numpy as np
import random

items = ['apple','banana','orange', 'car','bike','train','ship','plane','scooter', 'red','purple']
a = [random.sample(items, random.randint(2, 10)) for _ in range(1000)]
b = np.array(a)

%timeit [x[-1] for x in a] # 62.1 µs
%timeit [x[-1] for x in b] # 75.9 µs
f = np.frompyfunc(lambda x:x[-1], 1, 1)
%timeit f(b)  # 165 µs

import cytoolz
%timeit list(cytoolz.pluck(-1, a)) # 42.7 µs
%timeit list(cytoolz.pluck(-1, b)) # 75.8 µs

import pandas as pd
s = pd.Series(a)
%timeit s.str[-1] # 965 µs

即使您有DataFrame或Series对象,也可以先将其转换为列表:

%timeit s.tolist() #45.6 µs 

答案 2 :(得分:0)

使用循环理解:#!/bin/bash # ^^^^- NOT /bin/sh content=$(<"$ssh_key") # more efficient alternative to $(cat ...) # generate shell-quoted versions of your variables # these are safe to substitute into a script # ...even if the original content contains evil things like $(rm -rf /*) printf -v content_q '%q' "$content" printf -v new_user_q '%q' "$new_user" # use those shell-quoted versions remotely sshpass -f"$password_file" ssh "$host" bash -s <<EOF adduser ${new_user_q} printf '%s\n' ${content_q} >>/home/${new_user_q}/.ssh/authorized_keys EOF 可能只是一种有效而快速的方法,特别是如果列表足够长的话。但是既然你要求一个非循环的解决方案,这里有一种方法可以使用np.concatenate来获得一个扁平版本,然后使用适当的索引将其编入索引,以便选择每个列表的最终元素 -

np.array([i[-1] for i in arr],dtype=object)

np.concatenate(arr)[np.cumsum(map(len,arr))-1] 运算符的使用,它看起来不像向量化操作,但由于我们只使用它来获取列表的长度,因此该部分在运行时不应该很重。所以,我想这是一种几乎矢量化的方法。

示例运行 -

map

请注意,如果我们想要一个对象dtype数组,我们需要在编制索引之前转换为这样的dtype:In [166]: arr Out[166]: array([['apple', 'banana', 'orange'], ['car', 'bike', 'train', 'ship', 'plane', 'scooter'], ['red', 'purple']], dtype=object) In [167]: np.concatenate(arr)[np.cumsum(map(len,arr))-1] Out[167]: array(['orange', 'scooter', 'purple'], dtype='|S7')