【问题标题】:Is it possible to create Pandas vectorization in this use case?是否可以在此用例中创建 Pandas 矢量化?
【发布时间】:2021-04-04 21:39:23
【问题描述】:

我正在尝试制作一个与下面的.apply 方法具有相同目的的 Pandas 矢量化脚本:

concised_df['email_account_letter_or_number_only'] = concised_df.apply(lambda x: x['email_account'] if (str(x['email_account']).isdigit() or not bool(re.search('[a-zA-Z]', str(x['email_account'])))) else (re.sub('[^A-Za-z]+', '', x['email_account'])), axis=1) 

代码的逻辑是这样的:如果email_account 是全数字或者不包含字母,那么只需将email_account 存储为email_account_letter_or_number_only。否则,执行re.sub 以仅保留email_account_letter_or_number_only 的字母(换句话说,删除所有数字和特殊字符)。

我尝试使 Pandas 矢量化的原因是为了使我的方法更加优化。如本博客https://towardsdatascience.com/apply-function-to-pandas-dataframe-rows-76df74165ee4方法6.矢量化)所述,Pandas 矢量化比.apply 快得多。

这是我想要的输入和输出示例:

email_account email_account_letter_or_number_only
0018889 0018889
nacho.taro nachotaro
nachth45678 nachth
nacikita nacikita
nacia_art naciaart

我尝试过 Goole 搜索“带有 if else 条件的 Pandas 矢量化”,但到目前为止我能够找到的结果都引用了其他方法,例如 numpy.wherepd.DataFrame.loc (How to iterate a vectorized if/else statement over additional columns?) 而不是 Pandas 矢量化。

【问题讨论】:

  • 我知道这是后续行动,但如果您希望有人为您提供最佳解决方案,他们首先需要了解您的问题以及您正在使用的数据。首先提供 5-10 行数据作为文本(请不要使用图像),并提供预期的输出。还要解释代码试图做什么。代码漫游,数据讨论。
  • 有道理,@cs95。我正要跟进示例输出表,但我看到您或 Nick 已将表添加到其中。谢谢。我现在将在我的代码中添加更多描述。
  • 好的,试试df['email_account_letter_or_number_only'] = np.where(df['email_account'].str.isdigit(), df['email_account'], df['email_account'].str.replace(r'[\W_]+', '')) np.where 是相当矢量化的。
  • @cs95 但它输出['0018889', 'nachotaro', 'nachth45678', 'nacikita', 'naciaart'],因为'nachth45678'不匹配only keep letters (in other words, remove all numbers and special characters) for email_account_letter_or_number_only.
  • np.where(df['email_account'].str.isdigit(), df['email_account'], df['email_account'].str.replace(r'[\W_\d ]+', ''))

标签: python regex pandas string


【解决方案1】:
import io
import pandas as pd

df_str = '''
email_account   email_account_letter_or_number_only
0018889 0018889
nacho.taro  nachotaro
nachth45678 nachth
nacikita    nacikita
nacia_art   naciaart
'''
df = pd.read_csv(io.StringIO(df_str.strip()), sep='\s+', index_col=False)



# 1.replace the char that is not letter or number to ''
obj = df['email_account'].fillna('').str.replace('\W|_', '')
# 0        0018889
# 1      nachotaro
# 2    nachth45678
# 3       nacikita
# 4       naciaart
# Name: email_account, dtype: object



# 2.replace the digit to '' when the cell contains letters, regexp
cond = obj.str.contains('\D')
obj[cond] = obj[cond].str.replace('\d', '')
print(obj)

# 0      0018889
# 1    nachotaro
# 2       nachth
# 3     nacikita
# 4     naciaart
# Name: email_account, dtype: object


# result
df['tag'] = obj
df['email_account_letter_or_number_only'] == df['tag']
# 0    True
# 1    True
# 2    True
# 3    True
# 4    True
# dtype: bool

您还可以定义一个函数来处理数据,并映射或应用:

# def a function and apply, use pandas Series map
def data_clean(email):
    if pd.isna(email):
        return '' 
    else:
        email = re.sub('\W|_', '', email)
        if email.isdigit():
            pass
        else:
            email = re.sub('\d+', '', email)
        return email   


df['email_account'].map(data_clean) == df['tag']

我觉得这个方法比python原生for iteration更有效。


添加性能测试:

In [12]: import re
    ...: obj_r = df['email_account'].copy()
    ...: def fun1(obj_r):
    ...:     obj = obj_r.fillna('').str.replace('\W|_', '')
    ...:     cond = obj.str.contains('\D')
    ...:     obj[cond] = obj[cond].str.replace('\d', '')
    ...:     return obj
    ...:
    ...: def fun2(obj_r):
    ...:     obj = obj_r.map(data_clean)
    ...:     return obj
    ...:

In [13]: %timeit fun1(obj_r)
2.4 ms ± 197 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [14]: %timeit fun2(obj_r)
187 µs ± 7.56 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

【讨论】:

  • 很好的答案。与 apply() 方法相比,这种方法的性能如何?
  • 这是一个不错的开始,但我认为仅选择数字行有点脆弱。这里cond = obj.str.contains('\D') 应该在上一个替换步骤之前运行,否则您可能会错误地包含像“abc123_def”这样的行。
猜你喜欢
  • 2021-12-15
  • 1970-01-01
  • 2023-03-30
  • 2011-08-09
  • 2019-04-28
  • 1970-01-01
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
相关资源
最近更新 更多