使用findall python从推文中提取@mentions(给出不正确的结果)

时间:2017-10-08 17:05:40

标签: python regex pandas twitter mention

我有一个像这样的csv文件

text
RT @CritCareMed: New Article: Male-Predominant Plasma Transfusion Strategy for Preventing Transfusion-Related Acute Lung Injury... htp://…
#CRISPR Inversion of CTCF Sites Alters Genome Topology & Enhancer/Promoter Function in @CellCellPress htp://.co/HrjDwbm7NN
RT @gvwilson: Where's the theory for software engineering? Behind a paywall, that's where. htp://.co/1t3TymiF3M #semat #fail
RT @sciencemagazine: What’s killing off the sea stars? htp://.co/J19FnigwM9 #ecology
RT @MHendr1cks: Eve Marder describes a horror that is familiar to worm connectome gazers. htp://.co/AEqc7NOWoR via @nucAmbiguous htp://…

我想从推文文本中提取所有提及(以'@'开头)。到目前为止,我已经完成了这个

import pandas as pd
import re

mydata = pd.read_csv("C:/Users/file.csv")
X = mydata.ix[:,:]
X=X.iloc[:,:1] #I have multiple columns so I'm selecting the first column only that is 'text'

for i in range(X.shape[0]):
result = re.findall("(^|[^@\w])@(\w{1,25})", str(X.iloc[:i,:]))

print(result);

这里有两个问题: 第一:在str(X.iloc[:1,:])它给了我['CritCareMed']这不正确,因为它应该给我['CellCellPress'],在str(X.iloc[:2,:])它再次给我['CritCareMed']这是当然不好了。我得到的最终结果是

  

[('','CritCareMed'),('','gvwilson'),('','sciencemagazine')]

它不包括第二行中的提及以及最后一行中的两个提及。 我想要的应该是这样的:

enter image description here

如何实现这些结果?这只是一个示例数据,我的原始数据有很多推文,方法还可以吗?

3 个答案:

答案 0 :(得分:1)

您可以使用str.findall方法来避免for循环,使用负面隐藏替换(^|[^@\w]),这会形成您在正则表达式中不需要的另一个捕获组:

df['mention'] = df.text.str.findall(r'(?<![@\w])@(\w{1,25})').apply(','.join)
df
#                                                text   mention
#0  RT @CritCareMed: New Article: Male-Predominant...   CritCareMed
#1  #CRISPR Inversion of CTCF Sites Alters Genome ...   CellCellPress
#2  RT @gvwilson: Where's the theory for software ...   gvwilson
#3  RT @sciencemagazine: What’s killing off the se...   sciencemagazine
#4  RT @MHendr1cks: Eve Marder describes a horror ...   MHendr1cks,nucAmbiguous

同样X.iloc[:i,:]返回一个数据框,因此str(X.iloc[:i,:])为您提供数据框的字符串表示形式,它与单元格中的元素非常不同,从{提取实际字符串{1}}列,您可以使用text或更好的方式来遍历列,请使用iteritems

X.text.iloc[0]

答案 1 :(得分:1)

虽然您已经有了答案,但您甚至可以尝试优化整个导入过程:

import re, pandas as pd

rx = re.compile(r'@([^:\s]+)')

with open("test.txt") as fp:
    dft = ([line, ",".join(rx.findall(line))] for line in fp.readlines())

    df = pd.DataFrame(dft, columns = ['text', 'mention'])
    print(df)

<小时/> 产量:

                                                text                  mention
0  RT @CritCareMed: New Article: Male-Predominant...              CritCareMed
1  #CRISPR Inversion of CTCF Sites Alters Genome ...            CellCellPress
2  RT @gvwilson: Where's the theory for software ...                 gvwilson
3  RT @sciencemagazine: What’s killing off the se...          sciencemagazine
4  RT @MHendr1cks: Eve Marder describes a horror ...  MHendr1cks,nucAmbiguous

这可能会更快一些,因为您不需要在df已经构建后更改它。

答案 2 :(得分:1)

mydata['text'].str.findall(r'(?:(?<=\s)|(?<=^))@.*?(?=\s|$)')

与此相同:Extract hashtags from columns of a pandas dataframe,但要提及。

  • @.*?对单词开头进行非贪心匹配 带有标签
  • (?=\s|$)向前看单词的结尾或句子的结尾
  • (?:(?<=\s)|(?<=^))向后看以确保如果在单词中间使用@则不会出现误报

后面的正则表达式断言空格或句子开头必须在@字符之前。