求助:使用Polars从推文文本提取加密货币代码(Ticker)返回null
问题:Polars中从推文提取加密货币代码返回Null
背景
我有一个包含Date、User、Tweet三列的Polars DataFrame,Date是推文时间戳,User是推文者账号,Tweet是推文文本。示例数据如下:
import polars as pl data = b""" Date,User,Tweet 1.6781e6,user1,"$LQTY" 1.6781e6,user2,"$DF chart looks ready." 1.6781e6,user3,"Bought $LQTY." 1.6781e6,user4,"$PHB will easily reach 1.5$ as it did many times, the better your entry, the bigger the profits." """.strip() df = pl.read_csv(data)
示例DataFrame输出:
shape: (4, 3) ┌──────────┬───────┬─────────────────────────────────┐ │ Date ┆ User ┆ Tweet │ │ --- ┆ --- ┆ --- │ │ f64 ┆ str ┆ str │ ╞══════════╪═══════╪═════════════════════════════════╡ │ 1.6781e6 ┆ user1 ┆ $LQTY │ │ 1.6781e6 ┆ user2 ┆ $DF chart looks ready. │ │ 1.6781e6 ┆ user3 ┆ Bought $LQTY. │ │ 1.6781e6 ┆ user4 ┆ $PHB will easily reach 1.5$ as… │ └──────────┴───────┴─────────────────────────────────┘
需求
遍历所有推文,提取其中的加密货币代码(格式如$btc、$PHB),添加到名为Tickers的新列中。
尝试的代码及问题
我用以下代码尝试提取:
df = df.with_columns(pl.col("Tweet").str.extract(r'\$.*').alias('Tickers'))
预期能提取出代码,但实际Tickers列全为null:
┌──────────┬───────┬─────────────────────────────────┬─────────┐ │ Date ┆ User ┆ Tweet ┆ Tickers │ │ --- ┆ --- ┆ --- ┆ --- │ │ f64 ┆ str ┆ str ┆ str │ ╞══════════╪═══════╪═════════════════════════════════╪═════════╡ │ 1.6781e6 ┆ user1 ┆ $LQTY ┆ null │ │ 1.6781e6 ┆ user2 ┆ $DF chart looks ready. ┆ null │ │ 1.6781e6 ┆ user3 ┆ Bought $LQTY. ┆ null │ │ 1.6781e6 ┆ user4 ┆ $PHB will easily reach 1.5$ as… ┆ null │ └──────────┴───────┴─────────────────────────────────┴─────────┘
我的完整代码如下:
import polars as pl df = pl.read_csv('shilling.csv') df = df.select('Date', 'User', 'Tweet') df = df.filter(pl.col("Tweet").map_elements(lambda x: any(w.startswith("$") for w in x.split()))) # 转换Date列为datetime类型 df = df.with_columns(pl.col('Date').str.to_datetime("%Y-%m-%d %H:%M:%S%z")) # 转换Date列为时间戳(整数类型) df = df.with_columns(df['Date'].cast(int)) df = df.with_columns(df['Date'] / 1000000000) df = df.with_columns(pl.col("Tweet").str.extract(r'\$.*').alias('Tickers')) # df = df.with_columns(pl.col("Tweet").str.extract_regex(r'\$[A-Za-z0-9]+').alias('Tickers')) print(df)
解决方案
问题出在正则表达式和Polars的str.extract方法的使用逻辑上:
正则表达式错误:
\$.*会匹配$开头到字符串末尾的所有内容,但Polars的str.extract默认需要捕获组(即用()包裹要提取的目标内容),否则会返回null。另外,.*会包含空格、标点等非代码字符,我们需要精准匹配$后跟着字母数字的序列,直到遇到非字母数字字符为止。正确的实现方式:
提取每条推文的第一个加密货币代码
如果只需要每条推文里的第一个代码,使用带捕获组的正则:
# 提取带$符号的代码 df = df.with_columns( pl.col("Tweet").str.extract(r'(\$[A-Za-z0-9]+)').alias('Tickers') ) # 或提取不带$符号的代码 df = df.with_columns( pl.col("Tweet").str.extract(r'\$([A-Za-z0-9]+)').alias('Tickers') )
提取每条推文的所有加密货币代码
如果一条推文可能包含多个代码,用str.extract_all提取所有匹配项,可选择转成逗号分隔的字符串:
# 提取为列表格式 df = df.with_columns( pl.col("Tweet").str.extract_all(r'\$[A-Za-z0-9]+').alias('Tickers') ) # 转成逗号分隔的字符串 df = df.with_columns( pl.col("Tweet").str.extract_all(r'\$[A-Za-z0-9]+').list.join(',').alias('Tickers') )
示例处理结果
使用第一种方法处理示例DataFrame,会得到:
shape: (4, 4) ┌──────────┬───────┬─────────────────────────────────┬─────────┐ │ Date ┆ User ┆ Tweet ┆ Tickers │ │ --- ┆ --- ┆ --- ┆ --- │ │ f64 ┆ str ┆ str ┆ str │ ╞══════════╪═══════╪═════════════════════════════════╪═════════╡ │ 1.6781e6 ┆ user1 ┆ $LQTY ┆ $LQTY │ │ 1.6781e6 ┆ user2 ┆ $DF chart looks ready. ┆ $DF │ │ 1.6781e6 ┆ user3 ┆ Bought $LQTY. ┆ $LQTY │ │ 1.6781e6 ┆ user4 ┆ $PHB will easily reach 1.5$ as… ┆ $PHB │ └──────────┴───────┴─────────────────────────────────┴─────────┘
内容的提问来源于stack exchange,提问作者0xking
相关产品推荐
相关产品推荐

