【问题标题】:Pandas Apply lambda function null values熊猫应用 lambda 函数空值
【发布时间】:2016-05-05 21:16:01
【问题描述】:

我试图将一列分成两部分,但我知道我的数据中有空值。想象一下这个数据框:

df = pd.DataFrame(['fruit: apple','vegetable: asparagus',None, 'fruit: pear'], columns = ['text'])

df

                   text
0          fruit: apple
1  vegetable: asparagus
2                   None
3           fruit: pear

我想像这样把它分成多列:

df['cat'] = df['text'].apply(lambda x: 'unknown' if x == None else x.split(': ')[0])
df['value'] = df['text'].apply(lambda x: 'unknown' if x == None else x.split(': ')[1])

print df

                   text        cat      value
0          fruit: apple      fruit      apple
1  vegetable: asparagus  vegetable  asparagus
2                  None    unknown    unknown
3           fruit: pear      fruit       pear

但是,如果我有以下 df:

df = pd.DataFrame(['fruit: apple','vegetable: asparagus',np.nan, 'fruit: pear'], columns = ['text'])

拆分导致如下错误:

df['cat'] = df['text'].apply(lambda x: 'unknown' if x == np.nan else x.split(': ')[0])

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-159-8e5bca809635> in <module>()
      1 df = pd.DataFrame(['fruit: apple','vegetable: asparagus',np.nan, 'fruit: pear'], columns = ['text'])
      2 #df.columns = ['col_name']
----> 3 df['cat'] = df['text'].apply(lambda x: 'unknown' if x == np.nan else x.split(': ')[0])
      4 df['value'] = df['text'].apply(lambda x: 'unknown' if x == np.nan else x.split(': ')[1])

C:\Python27\lib\site-packages\pandas\core\series.pyc in apply(self, func, convert_dtype, args, **kwds)
   2158             values = lib.map_infer(values, lib.Timestamp)
   2159 
-> 2160         mapped = lib.map_infer(values, f, convert=convert_dtype)
   2161         if len(mapped) and isinstance(mapped[0], Series):
   2162             from pandas.core.frame import DataFrame

pandas\src\inference.pyx in pandas.lib.map_infer (pandas\lib.c:62187)()

<ipython-input-159-8e5bca809635> in <lambda>(x)
      1 df = pd.DataFrame(['fruit: apple','vegetable: asparagus',np.nan, 'fruit: pear'], columns = ['text'])
      2 #df.columns = ['col_name']
----> 3 df['cat'] = df['text'].apply(lambda x: 'unknown' if x == np.nan else x.split(': ')[0])
      4 df['value'] = df['text'].apply(lambda x: 'unknown' if x == np.nan else x.split(': ')[1])

AttributeError: 'float' object has no attribute 'split'

如何对 NaN 值进行同样的拆分? 通常有更好的方法来应用忽略空值的拆分函数吗?

想象这不是一个字符串示例,而是如果我有以下内容:

df = pd.DataFrame([2,4,6,8,10,np.nan,12], columns = ['numerics'])
df['numerics'].apply(lambda x: np.nan if pd.isnull(x) else x/2.0)

我觉得 Series.apply 几乎应该接受一个参数,指示它跳过空行并将它们作为空值输出。我还没有找到更好的 generic 方法来对系列进行转换,而无需手动避免空值。

【问题讨论】:

  • 试试df['cat'] = df['text'].apply(lambda x: 'unknown' if pd.isnull(x) else x.split(': ')[0])

标签: python pandas


【解决方案1】:

您可以使用Series.str.extract 方法,而不是使用自定义函数的apply

import numpy as np
import pandas as pd
# df = pd.DataFrame(['fruit: apple','vegetable: asparagus',None, 'fruit: pear'], 
#                   columns = ['text'])
df = pd.DataFrame(['fruit: apple','vegetable: asparagus',np.nan, 'fruit: pear'], 
                  columns = ['text'])
df[['cat', 'value']] = df['text'].str.extract(r'([^:]+):?(.*)', expand=True).fillna('unknown')
print(df)

产量

                   text        cat       value
0          fruit: apple      fruit       apple
1  vegetable: asparagus  vegetable   asparagus
2                   NaN    unknown     unknown
3           fruit: pear      fruit        pear

带有自定义函数的apply 通常比使用矢量化方法(如Series.str.extract)的等效代码慢。在底层,apply(带有不可矢量化的函数)本质上调用了 Python for-loop 中的自定义函数。


关于已编辑的问题:如果您有

df = pd.DataFrame([2,4,6,8,10,np.nan,12], columns = ['numerics'])

然后使用

In [207]: df['numerics']/2
Out[207]: 
0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
5    NaN
6    6.0
Name: numerics, dtype: float64

而不是

df['numerics'].apply(lambda x: np.nan if pd.isnull(x) else x/2.0)

再次,矢量化算术通过自定义函数击败 apply

In [210]: df = pd.concat([df]*100, ignore_index=True)

In [211]: %timeit df['numerics']/2
10000 loops, best of 3: 93.8 µs per loop

In [212]: %timeit df['numerics'].apply(lambda x: np.nan if pd.isnull(x) else x/2.0)
1000 loops, best of 3: 836 µs per loop

【讨论】:

  • 你用的是什么版本的熊猫?它适用于版本 0.18.0。
  • 17.0,但这是一个小问题 - 更新问题以反映。
  • @flyingmeatball,它有效。这是一个更复杂的测试用例:df = pd.DataFrame(['', 'fruit: apple',None,'vegetable: asparagus',np.nan, 'fruit: pear'], columns = ['text'])
  • @MaxU 我相信简单的案例是可行的,我不太担心这个例子的次要语法。我更感兴趣的是试图找到一种在 apply 语句中跳过空值的好方法。我发现自己需要相对频繁地这样做。
  • @unutbu 谢谢 - 我开始意识到我的基本问题的答案是没有一个好的方法来执行香草应用和跳过空值 - 这取决于个人柱子。我编辑的 df 更像是一个非文本操作的例子,我实际上不会在那种情况下使用 apply ,只是想找到一个我无法应用正则表达式的情况。感谢您的帮助。
猜你喜欢
  • 2016-09-17
  • 2017-01-24
  • 2018-02-09
  • 2023-01-18
  • 2022-01-04
  • 1970-01-01
  • 2020-10-20
  • 2014-07-04
  • 1970-01-01
相关资源
最近更新 更多