如何使用pd.熔化来解开数据框架,其中列共享一个前缀?



我正在尝试使用pd.melt解开我的数据,但到目前为止还没有成功。每一行都是一个业务,数据包含有关该业务和多个审查的信息。我希望我的数据将每个评论作为一行。

我的前150列每组15列,每组列名共享相同的模式reviews/n/对于0 < n < 9。(reviews/0/text,reviews/0/date,…,reviews/9/date)。数据框中接下来的65列包含更多关于业务的数据(例如business_idaddress),这些数据应该保留为id_variables。

我的当前数据如下所示:

tbody> <<tr>
business_id address reviews/0/date reviews/0/text reviews/1/date reviews/1/text reviews/1/text reviews/1/text1234501街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):

tbody> <<tr>
business_idaddressreview_date0review_date0review_date1review_text1
1234501街1/1/1990abc2/2/1995def

您可以获得所有非评论列的名称。

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

相关内容

  • 没有找到相关文章

最新更新