raz*_*raz 4 python regex unpivot melt pandas
我正在尝试使用逆透视数据pd.melt,但到目前为止尚未成功。每一行都是一个商家,数据包含该商家的信息和多个评论。我希望我的数据将每个评论作为一行。
我的前 150 列以 15 为一组,每个组的列名称都具有相同的reviews/n/模式0 < n < 9。( reviews/0/text,, reviews/0/date..., reviews/9/date)。数据框中接下来的 65 列包含更多有关业务的数据(例如business_id,address),这些数据应保留为 id_variables。
我当前的数据如下所示:
| 业务_id | 地址 | 评论/0/日期 | 评论/0/文本 | 评论/1/日期 | 评论/1/文本 |
|---|---|---|---|---|---|
| 12345 | 01街 | 1990年1月1日 | “abc” | 1995年2月2日 | “定义” |
我的新数据框应该将每个评论作为一行而不是每个业务,并且看起来像这样:
| 业务_id | 地址 | 评论号 | 审核日期 | 评论文本 |
|---|---|---|---|---|
| 12345 | 01街 | 0 | 1990年1月1日 | “abc” |
| 12345 | 01街 | 1 | 1995年2月2日 | “定义” |
我尝试使用pd.melt但无法成功编写对我有价值的代码。
您可以用来pandas.wide_to_long()做您想做的事。
但是,您需要首先将列从模式重命名reviews/N/COL为reviews/COL/N(或类似的名称),因为wide_to_long()只能根据前缀进行逆透视,而在列名称中,您有一个前缀和一个后缀。
您可以手动执行此操作,或者例如使用re模块和适当的正则表达式:
df = df.rename(columns=lambda x: re.sub('reviews/(\d)/(.*)', r'review_\2\1', x))
Run Code Online (Sandbox Code Playgroud)
之后,您的数据应如下所示(请注意更改后的列名):
| 业务_id | 地址 | 评论_日期0 | 评论文本0 | 评论_日期1 | 评论_文本1 |
|---|---|---|---|---|---|
| 12345 | 01街 | 1990年1月1日 | ABC | 1995年2月2日 | 定义 |
现在,您可以使用pandas.wide_to_long()并使用stubnames参数来指定逆透视时应分组的列的前缀。
df = pd.wide_to_long(df,
stubnames=['review_date','review_text'],
i=['business_id', 'address'],
j='review_number')
Run Code Online (Sandbox Code Playgroud)
最后,打电话.reset_index()来达到你所要求的结果。
完整示例:
import re
import pandas as pd
df = pd.DataFrame({'business_id': 12345,
'address': '01 street',
'reviews/0/date': '1/1/1990',
'reviews/0/text': 'abc',
'reviews/1/date': '2/2/1995',
'reviews/1/text': 'def'}, index = [0])
df = df.rename(columns=lambda x: re.sub('reviews/(\d)/(.*)', r'review_\2\1', x))
df = pd.wide_to_long(df,
stubnames=['review_date','review_text'],
i=['business_id', 'address'],
j='review_number').reset_index()
Run Code Online (Sandbox Code Playgroud)
结果:
| 业务_id | 地址 | 评论号 | 审核日期 | 评论文本 |
|---|---|---|---|---|
| 12345 | 01街 | 0 | 1990年1月1日 | ABC |
| 12345 | 01街 | 1 | 1995年2月2日 | 定义 |