我有一个空字符串列表:
test = ['foo', '', 'bar', '', 'baz']
以下代码将去除空字符串并返回所需的输出:
list(filter(None, test))
Out:['foo', 'bar', 'baz']
当我将列表变成一个numpy数组时,通过映射应用相同的功能不起作用:
test = np.array(['foo', '', 'bar', '', 'baz'], dtype='<U15')
def g(x):
return list(filter(None, x))
def array_map(x):
return np.array(list(map(g, x)))
array_map(test)
Out: array([list(['f', 'o', 'o']), list([]), list(['b', 'a', 'r']), list([]),
list(['b', 'a', 'z'])], dtype=object)
为什么会发生这种情况?从numpy数组中删除空字符串的正确,简单的方法是什么?
答案 0 :(得分:1)
当我将列表变成一个numpy数组时,通过映射应用相同的功能不起作用
正确;函数已经将您的源序列转换为您要创建数组的列表,因此无需进行任何映射。
为什么会这样
将g
映射到test
上意味着g
与 {em> x
的每个元素分别调用。 test
的元素是字符串;当list(filter(None, x))
是x
的字符串之一而求出test
时,filter
遍历字符串的 个字符。所有这些字符都通过过滤器,因此制作了一个包含它们的list
。因此,map
的{{1}}版本包含一堆字符列表,然后将这些字符列表传递给test
。
什么是从numpy数组中删除空字符串的正确,简单的方法是什么?
好吧,如果您想使用np.array
进行操作,看起来就像将Numpy数组传递给对filter
的 single 调用,然后构造一个新数组从结果。只是,filter
不会自动迭代生成的filter
对象,因此您必须创建例如首先列出。因此:
np.array
(请注意,如果要保留>>> np.array(list(filter(None, test)), dtype='<U15')
array(['foo', 'bar', 'baz'], dtype='<U15')
,则必须明确指定dtype
;否则Numpy会推断出足以满足数据需求的最小类型。)
但是,最好使用Numpy工具来完成此任务。从数组中删除数据的惯用方式是创建一个与所需元素匹配的掩码,并为其添加索引:< / p>
>>> test[test != '']
array(['foo', 'bar', 'baz'], dtype='<U15')
(如果您想删除所有虚假的东西(即无法满足if
条件的东西,则可以使用有点笨拙的nonzero
方法:test[test.nonzero()]
。)
答案 1 :(得分:0)
In [714]: test = ['foo', '', 'bar', '', 'baz']
我喜欢列表理解的表现力
In [715]: [s for s in test if s]
Out[715]: ['foo', 'bar', 'baz']
这种理解也适用于数组-尽管会更慢:
In [716]: aTest=np.array(test)
In [717]: aTest
Out[717]: array(['foo', '', 'bar', '', 'baz'], dtype='<U3')
In [718]: np.array([s for s in aTest if s])
Out[718]: array(['foo', 'bar', 'baz'], dtype='<U3')
数组的一个元素测试一个列表中的元素。
filter
的行为方式相同:
In [724]: list(filter(None, test))
Out[724]: ['foo', 'bar', 'baz']
In [725]: list(filter(None, aTest))
Out[725]: ['foo', 'bar', 'baz']
您的两个函数方法最终将list
应用于每个字符串,并将其拆分。外部map
将字符串传递给g
,而不是整个列表:
In [728]: def g(x):
...: return list(filter(None,x))
In [729]: list(map(g,test))
Out[729]: [['f', 'o', 'o'], [], ['b', 'a', 'r'], [], ['b', 'a', 'z']]
In [732]: [list(s) for s in test]
Out[732]: [['f', 'o', 'o'], [], ['b', 'a', 'r'], [], ['b', 'a', 'z']]
In [734]: list(g(test[0]))
Out[734]: ['f', 'o', 'o']
正如另一个答案中指出的那样,您可以执行数组过滤而无需进行python级迭代:
In [736]: aTest==''
Out[736]: array([False, True, False, True, False])
In [737]: aTest[aTest!='']
Out[737]: array(['foo', 'bar', 'baz'], dtype='<U3')
对于这个小样本,列表理解最快。我希望使用1000个字符串列表/数组,但数组方法会更好地扩展。
In [740]: timeit [s for s in test if s]
398 ns ± 10.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [741]: timeit aTest[aTest!='']
3.99 µs ± 158 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [743]: timeit list(filter(None, test))
503 ns ± 9.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)