我正在尝试使用pd.melt
解开我的数据,但到目前为止还没有成功。每一行都是一个业务,数据包含有关该业务和多个审查的信息。我希望我的数据将每个评论作为一行。
我的前150列每组15列,每组列名共享相同的模式reviews/n/
对于0 < n < 9
。(reviews/0/text
,reviews/0/date
,…,reviews/9/date
)。数据框中接下来的65列包含更多关于业务的数据(例如business_id
、address
),这些数据应该保留为id_variables。
我的当前数据如下所示:
business_id | address | reviews/0/date | reviews/0/text | reviews/1/date | reviews/1/text | reviews/1/text | reviews/1/text | tbody> <<tr>12345 | 01街 | 1/1/1990 | "abc" | 2/2/1995 | "def" |
---|
您可以使用pandas.wide_to_long()
做您想做的事情。
但是,您需要首先将您的列从模式reviews/N/COL
重命名为reviews/COL/N
(或类似的东西),因为wide_to_long()
只能基于前缀解除pivot,而在列名中,您有一个前缀和一个后缀。
您可以手动或例如使用re
模块和适当的正则表达式:
df = df.rename(columns=lambda x: re.sub('reviews/(d)/(.*)', r'review_21', x))
之后,您的数据应该看起来像这样(注意更改的colname):
business_id | address | review_date0 | review_date0 | review_date1 | review_text1 | 12345 | 01街 | 1/1/1990 | abc | 2/2/1995 | def |
---|
您可以获得所有非评论列的名称。
columns = df.columns[~df.columns.str.match(r'reviews/d+/')]
>>> columns
Index(['address', 'business_id'], dtype='object')
使用.melt()
df = df.melt(columns)
df['review_number'] = df['variable'].str.extract(r'reviews/(d+)')
df['variable'] = df['variable'].str.replace(r'reviews/d+/', 'review_')
>>> df
address business_id variable value review_number
0 street 1 review_date 1990-01-01 00:00:00 0
1 street 1 review_text "abc" 0
2 street 1 review_date 1995-02-02 00:00:00 1
3 street 1 review_text "def" 1
从那里你可以.pivot()
>>> df.pivot(index=columns.union(['review_number']).to_list(), columns='variable')
value
variable review_date review_text
address business_id review_number
street 1 0 1990-01-01 00:00:00 "abc"
1 1995-02-02 00:00:00 "def"
一个选项是使用pyjanitor的pivot_longer -在本例中,我们使用特殊占位符.value
来标识我们希望保留为标题的列的部分,而其余部分则被整理成一个新列:
# pip install pyjanitor
import pandas as pd
import janitor
(df
.pivot_longer(
index = ['business_id', 'address'],
names_to = ['.value', 'reviewnumber', '.value'],
names_pattern = r"(review)s/(d+)/(.+)"
)
.rename(columns = lambda f: f.replace('review', 'review_'))
)
business_id address review_number review_date review_text
0 12345 01 street 0 1/1/1990 abc
1 12345 01 street 1 2/2/1995 def
正则表达式提供了将标签提取到单独列中的灵活性。请注意,只要正则表达式正确,可以任意多次使用.value
。
另一个选项是pd.stack
,其中在转换之前拆分列-通常尽可能,如果可以,在翻转之前拆分列,而不是之后(数据大小越大,此选项的性能越高):
temp = df.set_index(['business_id', 'address'])
temp.columns = temp.columns.str.split("/", expand=True)
temp.columns.names = [None, 'review_numbers', None]
# quick route - the collapse_levels function
# is from pyjanitor
# temp.stack('review_numbers').collapse_levels().reset_index()
temp = temp.stack('review_numbers')
temp.columns = temp.columns.map("_".join)
temp.reset_index()
business_id address review_numbers reviews_date reviews_text
0 12345 01 street 0 1/1/1990 abc
1 12345 01 street 1 2/2/1995 def