我在Python 3上使用Pandas 0.19.1
。我在这些代码行上收到警告。我试图获取一个列表,其中包含Peter
列中字符串Unnamed: 5
所有的所有行号。
df = pd.read_excel(xls_path)
myRows = df[df['Unnamed: 5'] == 'Peter'].index.tolist()
警告:
"\Python36\lib\site-packages\pandas\core\ops.py:792: FutureWarning: elementwise
comparison failed; returning scalar, but in the future will perform
elementwise comparison
result = getattr(x, name)(y)"
这是什么是FutureWarning,我应该忽略它,因为它似乎有效。
答案 0 :(得分:51)
这个FutureWarning不是来自Pandas,它来自numpy,而且bug也会影响matplotlib和其他人,这里是如何重现更接近麻烦来源的警告:
import numpy as np
print(np.__version__) # Numpy version '1.12.0'
'x' in np.arange(5) #Future warning thrown here
FutureWarning: elementwise comparison failed; returning scalar instead, but in the
future will perform elementwise comparison
False
使用double equals运算符重现此错误的另一种方法:
import numpy as np
np.arange(5) == np.arange(5).astype(str) #FutureWarning thrown here
受此颤抖情节实施影响的这个FutureWarning的Matplotlib示例:https://matplotlib.org/examples/pylab_examples/quiver_demo.html
Numpy和本地python之间存在分歧,当你将字符串与numpy的数字类型进行比较时会发生什么。注意左操作数是python的草皮,一个原始字符串,中间操作是python的草皮,但右操作数是numpy的草皮。你应该返回一个Python风格的Scalar还是一个布尔的Numpy风格的ndarray? Numpy说bool的ndarray,Pythonic开发者不同意。经典的对峙。
如果数组中存在项目,它应该是元素比较还是标量?
如果你的代码或库使用in
或==
运算符来比较python字符串和numpy ndarrays,它们是不兼容的,所以如果你尝试它,它会返回一个标量,但是只是为了现在。警告表明将来这种行为可能会发生变化,因此如果python / numpy决定采用Numpy风格,那么你的代码就会在地毯上呕吐。
Numpy和Python正处于对峙状态,目前该操作会返回一个标量,但将来它可能会发生变化。
https://github.com/numpy/numpy/issues/6784
https://github.com/pandas-dev/pandas/issues/7830
锁定你的python版本和numpy,忽略警告并期望行为不会改变,或者将==
和in
的左右操作数转换为numpy类型或原语python数字类型。
全局禁止警告:
import warnings
import numpy as np
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(5)) #returns False, without Warning
逐行取消警告。
import warnings
import numpy as np
with warnings.catch_warnings():
warnings.simplefilter(action='ignore', category=FutureWarning)
print('x' in np.arange(2)) #returns False, warning is suppressed
print('x' in np.arange(10)) #returns False, Throws FutureWarning
只需按名称抑制警告,然后在旁边添加一个响亮的注释,提及当前版本的python和numpy,说这段代码很脆弱,需要这些版本并在此处添加链接。在路上踢罐头。
答案 1 :(得分:7)
无法击败Eric Leschinski的详细解答,但这是针对我认为尚未提及的原始问题的快速解决方法-将字符串放入列表中,并使用.isin
而不是{{ 1}}
例如:
==
答案 2 :(得分:2)
我对同一警告消息的体验是由TypeError引起的。
TypeError:无效的类型比较
因此,您可能需要检查packages
Unnamed: 5
以下是我可以复制警告信息的方法:
for x in df['Unnamed: 5']:
print(type(x)) # are they 'str' ?
希望它有所帮助。
答案 3 :(得分:2)
对此的一种快速解决方法是使用numpy.core.defchararray
。我也遇到了同样的警告消息,并且能够使用上述模块来解决它。
import numpy.core.defchararray as npd
resultdataset = npd.equal(dataset1, dataset2)
答案 4 :(得分:2)
Eric的答案很有帮助,说明了麻烦来自将Pandas系列(包含NumPy数组)与Python字符串进行比较。不幸的是,他的两个解决方法都只是抑制了警告。
要首先编写不会引起警告的代码,请显式地将字符串与Series的每个元素进行比较,并为每个元素获取单独的布尔值。例如,您可以使用map
和一个匿名函数。
myRows = df[df['Unnamed: 5'].map( lambda x: x == 'Peter' )].index.tolist()
答案 5 :(得分:1)
当我尝试将index_col
设置为将文件读取到Panda
的数据帧中时,会遇到相同的错误:
df = pd.read_csv('my_file.tsv', sep='\t', header=0, index_col=['0']) ## or same with the following
df = pd.read_csv('my_file.tsv', sep='\t', header=0, index_col=[0])
我以前从未遇到过这样的错误。我仍然试图找出背后的原因(使用@Eric Leschinski的解释和其他解释)。
无论如何,下面的方法可以解决问题,直到我找出原因为止:
df = pd.read_csv('my_file.tsv', sep='\t', header=0) ## not setting the index_col
df.set_index(['0'], inplace=True)
一旦弄清这种行为的原因,我将立即进行更新。
答案 6 :(得分:1)
在我的情况下,发生警告的原因仅在于布尔索引的常规类型-因为该系列只有np.nan。示范(熊猫1.0.3):
>>> import pandas as pd
>>> import numpy as np
>>> pd.Series([np.nan, 'Hi']) == 'Hi'
0 False
1 True
>>> pd.Series([np.nan, np.nan]) == 'Hi'
~/anaconda3/envs/ms3/lib/python3.7/site-packages/pandas/core/ops/array_ops.py:255: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
res_values = method(rvalues)
0 False
1 False
我认为在熊猫1.0中,他们确实希望您使用新的'string'
数据类型,该数据类型允许使用pd.NA
值:
>>> pd.Series([pd.NA, pd.NA]) == 'Hi'
0 False
1 False
>>> pd.Series([np.nan, np.nan], dtype='string') == 'Hi'
0 <NA>
1 <NA>
>>> (pd.Series([np.nan, np.nan], dtype='string') == 'Hi').fillna(False)
0 False
1 False
不喜欢他们在何时开始使用布尔索引等日常功能。
答案 7 :(得分:0)
如果您的阵列不是太大或者没有太多的阵列,那么您可能会强迫==
的左侧为字符串:
myRows = df[str(df['Unnamed: 5']) == 'Peter'].index.tolist()
但是如果df['Unnamed: 5']
是一个字符串,那么慢约1.5倍,如果df['Unnamed: 5']
是一个小的numpy数组(长度= 10),则慢25-30倍,如果它是慢的150-160倍一个长度为100的numpy数组(平均超过500次试验的次数)。
a = linspace(0, 5, 10)
b = linspace(0, 50, 100)
n = 500
string1 = 'Peter'
string2 = 'blargh'
times_a = zeros(n)
times_str_a = zeros(n)
times_s = zeros(n)
times_str_s = zeros(n)
times_b = zeros(n)
times_str_b = zeros(n)
for i in range(n):
t0 = time.time()
tmp1 = a == string1
t1 = time.time()
tmp2 = str(a) == string1
t2 = time.time()
tmp3 = string2 == string1
t3 = time.time()
tmp4 = str(string2) == string1
t4 = time.time()
tmp5 = b == string1
t5 = time.time()
tmp6 = str(b) == string1
t6 = time.time()
times_a[i] = t1 - t0
times_str_a[i] = t2 - t1
times_s[i] = t3 - t2
times_str_s[i] = t4 - t3
times_b[i] = t5 - t4
times_str_b[i] = t6 - t5
print('Small array:')
print('Time to compare without str conversion: {} s. With str conversion: {} s'.format(mean(times_a), mean(times_str_a)))
print('Ratio of time with/without string conversion: {}'.format(mean(times_str_a)/mean(times_a)))
print('\nBig array')
print('Time to compare without str conversion: {} s. With str conversion: {} s'.format(mean(times_b), mean(times_str_b)))
print(mean(times_str_b)/mean(times_b))
print('\nString')
print('Time to compare without str conversion: {} s. With str conversion: {} s'.format(mean(times_s), mean(times_str_s)))
print('Ratio of time with/without string conversion: {}'.format(mean(times_str_s)/mean(times_s)))
结果:
Small array:
Time to compare without str conversion: 6.58464431763e-06 s. With str conversion: 0.000173756599426 s
Ratio of time with/without string conversion: 26.3881526541
Big array
Time to compare without str conversion: 5.44309616089e-06 s. With str conversion: 0.000870866775513 s
159.99474375821288
String
Time to compare without str conversion: 5.89370727539e-07 s. With str conversion: 8.30173492432e-07 s
Ratio of time with/without string conversion: 1.40857605178
答案 8 :(得分:0)
之所以收到此警告,是因为我认为我的列中包含空字符串,但是在检查时,它包含了np.nan!
if df['column'] == '':
将我的列更改为空字符串有帮助:)
答案 9 :(得分:0)
我已经比较了一些可能的方法,包括熊猫,几种numpy方法和列表理解方法。
首先,让我们从基线开始:
>>> import numpy as np
>>> import operator
>>> import pandas as pd
>>> x = [1, 2, 1, 2]
>>> %time count = np.sum(np.equal(1, x))
>>> print("Count {} using numpy equal with ints".format(count))
CPU times: user 52 µs, sys: 0 ns, total: 52 µs
Wall time: 56 µs
Count 2 using numpy equal with ints
因此,我们的基准是该计数应该正确2
,而我们应该占用50 us
。
现在,我们尝试使用朴素的方法:
>>> x = ['s', 'b', 's', 'b']
>>> %time count = np.sum(np.equal('s', x))
>>> print("Count {} using numpy equal".format(count))
CPU times: user 145 µs, sys: 24 µs, total: 169 µs
Wall time: 158 µs
Count NotImplemented using numpy equal
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/ipykernel_launcher.py:1: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
"""Entry point for launching an IPython kernel.
在这里,我们得到了错误的答案(NotImplemented != 2
),这花了我们很长时间,并且引发了警告。
因此,我们将尝试另一种朴素的方法:
>>> %time count = np.sum(x == 's')
>>> print("Count {} using ==".format(count))
CPU times: user 46 µs, sys: 1 µs, total: 47 µs
Wall time: 50.1 µs
Count 0 using ==
同样,答案错误(0 != 2
)。这更加隐蔽,因为没有后续警告(0
可以像2
那样传递)。
现在,让我们尝试一个列表理解:
>>> %time count = np.sum([operator.eq(_x, 's') for _x in x])
>>> print("Count {} using list comprehension".format(count))
CPU times: user 55 µs, sys: 1 µs, total: 56 µs
Wall time: 60.3 µs
Count 2 using list comprehension
我们在这里得到了正确的答案,而且速度很快!
另一种可能性,pandas
:
>>> y = pd.Series(x)
>>> %time count = np.sum(y == 's')
>>> print("Count {} using pandas ==".format(count))
CPU times: user 453 µs, sys: 31 µs, total: 484 µs
Wall time: 463 µs
Count 2 using pandas ==
慢,但是正确!
最后,我将要使用的选项是:将numpy
数组强制转换为object
类型:
>>> x = np.array(['s', 'b', 's', 'b']).astype(object)
>>> %time count = np.sum(np.equal('s', x))
>>> print("Count {} using numpy equal".format(count))
CPU times: user 50 µs, sys: 1 µs, total: 51 µs
Wall time: 55.1 µs
Count 2 using numpy equal
快速正确!
答案 10 :(得分:0)
我有导致错误的代码:
for t in dfObj['time']:
if type(t) == str:
the_date = dateutil.parser.parse(t)
loc_dt_int = int(the_date.timestamp())
dfObj.loc[t == dfObj.time, 'time'] = loc_dt_int
我将其更改为此:
for t in dfObj['time']:
try:
the_date = dateutil.parser.parse(t)
loc_dt_int = int(the_date.timestamp())
dfObj.loc[t == dfObj.time, 'time'] = loc_dt_int
except Exception as e:
print(e)
continue
为避免比较,它会引发警告-如上所述。我只需要避免由于for循环中的dfObj.loc
而导致的异常,也许有一种方法可以告诉它不要检查已更改的行。