如何使用 pd.melt 取消透视列共享前缀的数据框?

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_idaddress),这些数据应保留为 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但无法成功编写对我有价值的代码。

bud*_*mat 6

您可以用来pandas.wide_to_long()做您想做的事。

但是,您需要首先将列从模式重命名reviews/N/COLreviews/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日 定义