【问题标题】:How to use pandas apply to replace iterrows?如何使用 pandas apply 来替换 iterrows?
【发布时间】:2021-10-17 15:36:02
【问题描述】:

我正在根据新闻标题计算数据集中每一行的情绪值。我使用iterrows 来实现这一点:

field = 'headline'
dfp = pd.DataFrame(columns=('pos', 'neg', 'neu'))

tokenizer = AutoTokenizer.from_pretrained("ProsusAI/finbert")

model = AutoModelForSequenceClassification.from_pretrained("ProsusAI/finbert")

for index, row in df.iterrows():
    text = row[field]
    encoded_input = tokenizer(text, return_tensors='pt')
    output = model(**encoded_input)
    probs = torch.nn.functional.softmax(output[0], dim=-1)
    probs_arr = probs.cpu().detach().numpy()
    dfp = dfp.append({'pos': probs_arr[0][0],
                      'neg': probs_arr[0][1],
                      'neu': probs_arr[0][2]
                     }, ignore_index=True)

但是,处理时间太长(运行时间>30 分钟,但尚未完成)。我的数据集中有 16.6k 行。

这是数据集的一小部分:

    datetime            headline
0   2020-03-17 16:57:07 12 best noise-cancelling headphones: In-ear an...
1   2020-06-08 14:00:55 5G Stocks To Buy And Watch: Pricing of 5G Smar...
2   2020-06-19 10:00:00 10 best wireless printers that will make your ...
3   2020-08-19 00:00:00 Apple Confirms Solid New iOS 14 Security Move ...
4   2020-08-19 00:00:00 Apple Becomes First U.S. Company Worth More Th...

我已经读到iterrows 在大多数情况下不推荐,除非数据集很小并且优化不是问题。它的替代方案似乎是使用apply,因为apply 遍历每个pandas 行并进行了优化。

我阅读的一些 SO 主题建议将创建一个函数并在 apply 中运行它。这是我尝试的:

def calPred(text):
    encoded_input = tokenizer(text, return_tensors='pt')
    output = model(**encoded_input)
    probs = torch.nn.functional.softmax(output[0], dim=-1)
    probs_arr = probs.cpu().detach().numpy()
    dfp = dfp.append({'pos': probs_arr[0][0],
                      'neg': probs_arr[0][1],
                      'neu': probs_arr[0][2]
                     }, ignore_index=True)

df['headline'].apply(lambda x: calPred(x))

它返回了一个错误UnboundLocalError: local variable 'dfp' referenced before assignment

感谢有人可以指导我如何正确优化和使用apply。提前致谢。

【问题讨论】:

    标签: python pandas if-statement lambda apply


    【解决方案1】:

    您的代码的问题在于,当您执行 dfp = dfp.append... 时,dfp 已被定义为全局并且您无法重新分配它(使用另一个变量名),即 dfp_temp = dfp.append...

    但是我认为 apply 不是您想要的。 ML 中的大多数模型将采用类似数组的形式作为输入,因此您可以传递模型中的整个列(或至少是其中的一大块),而不是每一行。

    类似的东西

    field = 'headline'
    
    tokenizer = AutoTokenizer.from_pretrained("ProsusAI/finbert")
    
    model = AutoModelForSequenceClassification.from_pretrained("ProsusAI/finbert")
    
    texts = df[field].values
    encoded_input = tokenizer(texts, return_tensors='pt')
    output = model(encoded_input)
    probs = torch.nn.functional.softmax(output, dim=-1)
    probs = probs.cpu().detach().numpy()
    
    dfp = pd.DataFrame({
        'pos': probs[:, 0],
        'neg': probs[:, 1],
        'neu': probs[:, 2]
    })
    

    编辑:Tokenizer 不支持数组

    您可以尝试像这样对标记器进行矢量化

    注意:np.vectorize 和 apply 不会给你任何显着的提升,因为它们仍然会迭代每个元素。但是,最好尽可能少地使用 apply 和 np.vectorize。

    ...
    tokenizer_func = lambda text: tokenizer(text, return_tensors='pt')
    encoded_input = np.vectorize(tokenizer_func)(texts)
    ...
    

    【讨论】:

    • 请注意,np.vectorize 不会编译代码,并且不会比 python 中的 for 循环快。它所改变的只是函数签名。
    • 好吧,它是 python,你不能真正编译代码,除非你使用像 numba 这样的 jit,我认为它无论如何都不会工作。但是,它会比使用 apply 并在每一行上运行模型更快。
    • 当然,只是指出 np.vectorize 相对于 df.apply 或 df.iterrows 的性能而言并没有真正的帮助
    • 之所以如此,是因为模型评估了一次。它是矢量化还是应用都没有关系。他可以使用申请标记器。要点是不要在模型评估的每一行上使用 apply。
    • 我完全同意,但我认为他对此无能为力。当我不使用移动设备时,我会将其添加到答案中。
    猜你喜欢
    • 2023-03-24
    • 2020-08-02
    • 2022-12-22
    • 2021-01-20
    • 2018-06-26
    • 2023-03-03
    • 2022-11-25
    • 2021-09-24
    • 2019-12-21
    相关资源
    最近更新 更多