接着我上一个问题:Pyjanitor pivot_longer多列集,具有公共分组变量和id列
在我的最后一个问题中,我给出的数据集对于我所遇到的问题来说过于简化了。我已经改变了列名来代表我的数据集中的列名,因为我不知道如何在pivot_longer
中使用regex来修复它们。在我给出的模型数据集中,列是用以下模式编写的:number_word
,但在我的数据集中,列是任意顺序的,从不用下划线分隔(例如,wordnumber)。
注意,每个列集的编号需要是相同的分组变量。因此,每个数字都应该有一个评级、估计和类型。
数据集df = pd.DataFrame({
'id': [1, 1, 1],
'ratingfirst': [1, 2, 3],
'ratingsecond': [2.8, 2.9, 2.2],
'ratingthird': [3.4, 3.8, 2.9],
'firstestimate': [1.2, 2.4, 2.8],
'secondestimate': [2.4, 3, 2.4],
'thirdestimate':[3.4, 3.8, 2.9],
'firsttype': ['red', 'green', 'blue'],
'secondtype': ['red', 'green', 'yellow'],
'thirdtype': ['red', 'red', 'blue'],
})
期望输出值
我想要的输出的标题如下:
我认为最简单的方法是将您的列与上一个问题中使用的列对齐,例如:
def fix_col_header(s, d):
for word, word_replace in d.items():
s = s.replace(word, word_replace)
if s.startswith("_"):
s = s[len(word_replace):] + s[:len(word_replace)]
return s
d = {"first":"_first", "second":"_second", "third": "_third"}
df.columns = [fix_col_header(col, d) for col in df.columns]
这将给列:
id, rating_first, rating_second, rating_third, estimate_first, estimate_second, estimate_third, type_first, type_second, type_third
现在您可以应用上一个问题的解决方案(注意,类别和值是互换的)。为了完整起见,我在这里添加了它:
import janitor
(df
.pivot_longer(
column_names="*_*",
names_to = (".value", "category"),
names_sep="_")
)
pivot_longer
支持多个.value
-您可以利用这一点来重塑您的数据框,使用names_sep
参数:
# pip install pyjanitor
import pandas as pd
import janitor
(df
.pivot_longer(
index='id',
names_to = (".value", "category", ".value"),
names_sep = "(first|second|third)")
)
id category rating estimate type
0 1 first 1.0 1.2 red
1 1 first 2.0 2.4 green
2 1 first 3.0 2.8 blue
3 1 second 2.8 2.4 red
4 1 second 2.9 3.0 green
5 1 second 2.2 2.4 yellow
6 1 third 3.4 3.4 red
7 1 third 3.8 3.8 red
8 1 third 2.9 2.9 blue
如果你看一下分解,你可以看到这里发生了什么:
df.columns[1:].str.split("(first|second|third)")
Index([ ['rating', 'first', ''], ['rating', 'second', ''],
['rating', 'third', ''], ['', 'first', 'estimate'],
['', 'second', 'estimate'], ['', 'third', 'estimate'],
['', 'first', 'type'], ['', 'second', 'type'],
['', 'third', 'type']],
dtype='object')
注意我们有三个条目,其中一个是空字符串。这与我们的names_to
参数匹配->(".value", "category", ".value")
;一旦pivot_longer
匹配,它就会在最终输出中将.value
合并为一个,因此对于['rating', 'first', '']
,它将取出('rating', '')
,并最终将它们合并为一个->rating
,并以此类推。
pd.stack
:
temp = df.set_index('id')
temp.columns = temp.columns.str.split("(first|second|third)", expand = True)
temp.columns.names = [None, 'category', None]
temp = temp.stack('category')
temp.columns = temp.columns.map("".join)
temp.reset_index()
id category estimate type rating
0 1 first 1.2 red 1.0
1 1 second 2.4 red 2.8
2 1 third 3.4 red 3.4
3 1 first 2.4 green 2.0
4 1 second 3.0 green 2.9
5 1 third 3.8 red 3.8
6 1 first 2.8 blue 3.0
7 1 second 2.4 yellow 2.2
8 1 third 2.9 blue 2.9