Python 矢量化自定义函数未按预期在中工作
以pycon talk为来源Python 矢量化自定义函数未按预期在中工作,python,python-3.x,pandas,data-science,vectorization,Python,Python 3.x,Pandas,Data Science,Vectorization,以pycon talk为来源 def clean_string(item): if type(item)==type(1): return item else: return np.nan dataframe对象有一列包含数字和字符串数据,我想将字符串更改为np.nan 同时保持数字数据不变 这种方法很有效 df['Energy Supply'].apply(clean_string) 但是当我尝试使用矢量化时,所有列项目的值都变为np.na
def clean_string(item):
if type(item)==type(1):
return item
else:
return np.nan
dataframe对象有一列包含数字和字符串数据,我想将字符串更改为np.nan
同时保持数字数据不变
这种方法很有效
df['Energy Supply'].apply(clean_string)
但是当我尝试使用矢量化时,所有列项目的值都变为np.nan
df['Energy Supply'] = clean_string(df['Energy Supply']) # vectorisation
但是上面的方法是将所有项转换为np.nan
。我相信这是因为type(item)
在clean_string
函数中是pd.Series
类型
有没有办法克服这个问题
PS:pandas中的矢量化操作并不总是可能的,我是pandas的初学者。我不知道有一种内置的矢量化方法来获取系列中元素的类型,因此您的
.apply()
解决方案可能是最好的方法
在第二种情况下,代码不起作用的原因是将整个序列传递给clean_string()
函数。它将序列的类型与type(1)
进行比较,后者为False
,然后返回一个值np.nan
。Pandas在将该值分配回df时会自动广播该值,因此会得到一列NaN
。为了避免这种情况,您必须在clean_string()
函数的系列中循环所有元素
出于好奇,我尝试了其他几种方法,看看它们是否比您的版本更快。为了测试,我创建了10000和100000元素pd.Series
,其中交替使用整数和字符串值:
将numpy导入为np
作为pd进口熊猫
s=pd.系列(如果i%2==0,则i为范围(10000)内的i的其他str(i))
s2=pd.系列(如果i%2==0,则i为范围(100000)内的i的其他str(i))
这些测试是使用pandas 1.0.3和python 3.8完成的
使用clean_string()
[]中的:%timeit s.apply(清除字符串)
每个回路3.75 ms±14.4µs(7次运行的平均值±标准偏差,每个100个回路)
在[]中:%timeit s2.apply(清除字符串)
每个回路39.5 ms±301µs(7次运行的平均值±标准偏差,每个10个回路)
Series.str
方法
测试字符串与非字符串的另一种方法是在序列上使用内置的.str
函数,例如,如果应用.str.len()
,它将为序列中的任何非字符串返回NaN
。这些在熊猫文档中甚至被称为“”,因此它们可能会更有效
[]中的:%timeit s.mask(s.str.len()>0)
每个回路6 ms±39.2µs(7次运行的平均值±标准偏差,每个100个回路)
在[]中:%timeit s2.mask(s2.str.len()>0)
每个回路56.8 ms±142µs(7次运行的平均值±标准偏差,每个10个回路)
不幸的是,这种方法比.apply()
慢。尽管被“矢量化”,但这看起来并不是一个更好的方法。它与clean_string()
的逻辑也不完全相同,因为它测试的是字符串元素,而不是整数元素
将类型
直接应用于序列
基于,我决定使用.apply()
和type
进行测试,以获得每个元素的类型。一旦我们知道了类型,比较int
,并使用.mask()
方法将任何非整数转换为NaN
[]中的:%timeit s.mask(s.apply(type)!=int)
每个回路1.88 ms±4.7µs(7次运行的平均值±标准偏差,每个1000个回路)
在[]中:%timeit s2.mask(s2.apply(type)!=int)
每个回路15.2 ms±32.8µs(7次运行的平均值±标准偏差,每个100个回路)
这是我发现的最快的方法