在子字符串上熔化和合并 - Python & Pandas
Melt and Merge on Substring - Python & Pandas
我有数据,其中包含类似
的数据
id name model_# ms bp1 cd1 sf1 sa1 rq1 bp2 cd2 sf2 sa2 rq2 ...
1 John 23984 1 23 234 124 25 252 252 62 194 234 234 ...
2 John 23984 2 234 234 242 62 262 622 262 622 26 262 ...
数百个模型,最多 10 毫秒,变量计数最多 21。
我通常使用 pd.melt 在我查看 bp1:bp21 或其他任何地方进行分析。我目前需要创建一个熔体,在其中查看 bp1 值和 rq 1 值。
我希望有效地创建这样的东西:
id model_# ms variable_x value_x variable_y value_y
0 113 77515 1 bp1 23 rq1 252
1 113 77515 1 bp2 252 rq2 262
2 113 77515 1 bp3 26 rq3 311
目前我能做的最好的事情是:
id model_# ms variable_x value_x variable_y value_y
0 113 77515 1 bp1 23 rq1 252
1 113 77515 1 bp1 23 rq2 262
2 113 77515 1 bp1 23 rq3 311
3 113 77515 1 bp1 23 rq4 246
来自:
df = pd.melt(dat, id_vars=['id', 'mod_req', 'ms'], value_vars=bp)
df1 = pd.melt(dat, id_vars=['id', 'mod_req', 'ms'], value_vars=rq)
df2 = pd.merge(df,df1, on=['id', 'mod_req', 'ms'])
有没有简单的方法来合并子字符串,使 bp1 与 rq1 连接等等?这意味着采用一个仅查看 bp1:bp21 的熔化数据框和另一个熔化数据框 rq1:rq21 并根据子字符串值(bp1 rq1,而不是 bp1 rq2)
进行合并
解决方案
设置索引...
使用巧妙的列 groupby
...
apply
的另一个聪明的功能...
d1 = df.set_index(['id', 'name', 'model_#', 'ms'])
def melt_(df):
id_vars = df.index.names
return df.reset_index().melt(id_vars=id_vars).set_index(id_vars)
d2 = d1.groupby(d1.columns.str.extract('(\D+)', expand=False), axis=1).apply(melt_)
d2.columns = d2.columns.swaplevel(0, 1).map('_'.join)
d2.reset_index()
id name model_# ms variable_bp value_bp variable_cd value_cd variable_rq value_rq variable_sa value_sa variable_sf value_sf
0 1 John 23984 1 bp1 23 cd1 234 rq1 252 sa1 25 sf1 124
1 2 John 23984 2 bp1 234 cd1 234 rq1 262 sa1 62 sf1 242
2 1 John 23984 1 bp2 252 cd2 62 rq2 234 sa2 234 sf2 194
3 2 John 23984 2 bp2 622 cd2 262 rq2 262 sa2 26 sf2 622
过度功能化
e = lambda d, n: dict(zip(n, d.dtypes))
i = lambda d, n: pd.DataFrame(d.values, d.index, n).astype(e(d, n))
h = lambda d: i(d, d.columns.map(fmt)).reset_index()
m = lambda d: d.reset_index().melt(cols).set_index(cols)
fmt = '{0[1]}_{0[0]}'.format
cols = ['id', 'name', 'model_#', 'ms']
d1 = df.set_index(cols)
g = d1.columns.str.extract('(\D+)', expand=False)
d1.groupby(g, axis=1).apply(m).pipe(h)
id name model_# ms variable_bp value_bp variable_cd value_cd variable_rq value_rq variable_sa value_sa variable_sf value_sf
0 1 John 23984 1 bp1 23 cd1 234 rq1 252 sa1 25 sf1 124
1 2 John 23984 2 bp1 234 cd1 234 rq1 262 sa1 62 sf1 242
2 1 John 23984 1 bp2 252 cd2 62 rq2 234 sa2 234 sf2 194
3 2 John 23984 2 bp2 622 cd2 262 rq2 262 sa2 26 sf2 622
旧答案
这远非漂亮,我什至不确定这是你想要的。
d1 = df.set_index(['id', 'name', 'model_#', 'ms'])
cidx = pd.MultiIndex.from_tuples(
d1.columns.to_series().str.extract('(\D+)(\d+)', expand=False).values.tolist(),
names=[None, 'variable']
)
d1.columns = cidx
d2 = d1.sort_index(axis=1).stack()
variables = pd.DataFrame(
(d2.columns + d2.index.get_level_values('variable')[:, None]).tolist(),
d2.index, d2.columns
)
d3 = pd.concat(
[variables, d2], axis=1, keys=['variable', 'value']
).reset_index('variable', drop=True).sort_index(axis=1, level=1, sort_remaining=False)
d3.columns = d3.columns.map('_'.join)
d3.reset_index()
id name model_# ms variable_bp value_bp variable_cd value_cd variable_rq value_rq variable_sa value_sa variable_sf value_sf
0 1 John 23984 1 bp1 23 cd1 234 rq1 252 sa1 25 sf1 124
1 1 John 23984 1 bp2 252 cd2 62 rq2 234 sa2 234 sf2 194
2 2 John 23984 2 bp1 234 cd1 234 rq1 262 sa1 62 sf1 242
3 2 John 23984 2 bp2 622 cd2 262 rq2 262 sa2 26 sf2 622
一个选项是 pivot_longer from pyjanitor,使用正则表达式列表,利用排序 (bp1
、rq1
、bp2
、rq2
, ...):
# currently in dev
# pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
import pandas as pd
import janitor
df.pivot_longer(
index = ['id', 'name', 'model_#'],
names_to = ('variable_x', 'variable_y'),
values_to = ['values_x', 'values_y'],
names_pattern = ['bp', 'rq'])
id name model_# variable_x values_x variable_y values_y
0 1 John 23984 bp1 23 rq1 252
1 2 John 23984 bp1 234 rq1 262
2 1 John 23984 bp2 252 rq2 234
3 2 John 23984 bp2 622 rq2 262
我有数据,其中包含类似
的数据id name model_# ms bp1 cd1 sf1 sa1 rq1 bp2 cd2 sf2 sa2 rq2 ...
1 John 23984 1 23 234 124 25 252 252 62 194 234 234 ...
2 John 23984 2 234 234 242 62 262 622 262 622 26 262 ...
数百个模型,最多 10 毫秒,变量计数最多 21。
我通常使用 pd.melt 在我查看 bp1:bp21 或其他任何地方进行分析。我目前需要创建一个熔体,在其中查看 bp1 值和 rq 1 值。
我希望有效地创建这样的东西:
id model_# ms variable_x value_x variable_y value_y
0 113 77515 1 bp1 23 rq1 252
1 113 77515 1 bp2 252 rq2 262
2 113 77515 1 bp3 26 rq3 311
目前我能做的最好的事情是:
id model_# ms variable_x value_x variable_y value_y
0 113 77515 1 bp1 23 rq1 252
1 113 77515 1 bp1 23 rq2 262
2 113 77515 1 bp1 23 rq3 311
3 113 77515 1 bp1 23 rq4 246
来自:
df = pd.melt(dat, id_vars=['id', 'mod_req', 'ms'], value_vars=bp)
df1 = pd.melt(dat, id_vars=['id', 'mod_req', 'ms'], value_vars=rq)
df2 = pd.merge(df,df1, on=['id', 'mod_req', 'ms'])
有没有简单的方法来合并子字符串,使 bp1 与 rq1 连接等等?这意味着采用一个仅查看 bp1:bp21 的熔化数据框和另一个熔化数据框 rq1:rq21 并根据子字符串值(bp1 rq1,而不是 bp1 rq2)
进行合并解决方案
设置索引...
使用巧妙的列 groupby
...
apply
的另一个聪明的功能...
d1 = df.set_index(['id', 'name', 'model_#', 'ms'])
def melt_(df):
id_vars = df.index.names
return df.reset_index().melt(id_vars=id_vars).set_index(id_vars)
d2 = d1.groupby(d1.columns.str.extract('(\D+)', expand=False), axis=1).apply(melt_)
d2.columns = d2.columns.swaplevel(0, 1).map('_'.join)
d2.reset_index()
id name model_# ms variable_bp value_bp variable_cd value_cd variable_rq value_rq variable_sa value_sa variable_sf value_sf
0 1 John 23984 1 bp1 23 cd1 234 rq1 252 sa1 25 sf1 124
1 2 John 23984 2 bp1 234 cd1 234 rq1 262 sa1 62 sf1 242
2 1 John 23984 1 bp2 252 cd2 62 rq2 234 sa2 234 sf2 194
3 2 John 23984 2 bp2 622 cd2 262 rq2 262 sa2 26 sf2 622
过度功能化
e = lambda d, n: dict(zip(n, d.dtypes))
i = lambda d, n: pd.DataFrame(d.values, d.index, n).astype(e(d, n))
h = lambda d: i(d, d.columns.map(fmt)).reset_index()
m = lambda d: d.reset_index().melt(cols).set_index(cols)
fmt = '{0[1]}_{0[0]}'.format
cols = ['id', 'name', 'model_#', 'ms']
d1 = df.set_index(cols)
g = d1.columns.str.extract('(\D+)', expand=False)
d1.groupby(g, axis=1).apply(m).pipe(h)
id name model_# ms variable_bp value_bp variable_cd value_cd variable_rq value_rq variable_sa value_sa variable_sf value_sf
0 1 John 23984 1 bp1 23 cd1 234 rq1 252 sa1 25 sf1 124
1 2 John 23984 2 bp1 234 cd1 234 rq1 262 sa1 62 sf1 242
2 1 John 23984 1 bp2 252 cd2 62 rq2 234 sa2 234 sf2 194
3 2 John 23984 2 bp2 622 cd2 262 rq2 262 sa2 26 sf2 622
旧答案
这远非漂亮,我什至不确定这是你想要的。
d1 = df.set_index(['id', 'name', 'model_#', 'ms'])
cidx = pd.MultiIndex.from_tuples(
d1.columns.to_series().str.extract('(\D+)(\d+)', expand=False).values.tolist(),
names=[None, 'variable']
)
d1.columns = cidx
d2 = d1.sort_index(axis=1).stack()
variables = pd.DataFrame(
(d2.columns + d2.index.get_level_values('variable')[:, None]).tolist(),
d2.index, d2.columns
)
d3 = pd.concat(
[variables, d2], axis=1, keys=['variable', 'value']
).reset_index('variable', drop=True).sort_index(axis=1, level=1, sort_remaining=False)
d3.columns = d3.columns.map('_'.join)
d3.reset_index()
id name model_# ms variable_bp value_bp variable_cd value_cd variable_rq value_rq variable_sa value_sa variable_sf value_sf
0 1 John 23984 1 bp1 23 cd1 234 rq1 252 sa1 25 sf1 124
1 1 John 23984 1 bp2 252 cd2 62 rq2 234 sa2 234 sf2 194
2 2 John 23984 2 bp1 234 cd1 234 rq1 262 sa1 62 sf1 242
3 2 John 23984 2 bp2 622 cd2 262 rq2 262 sa2 26 sf2 622
一个选项是 pivot_longer from pyjanitor,使用正则表达式列表,利用排序 (bp1
、rq1
、bp2
、rq2
, ...):
# currently in dev
# pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
import pandas as pd
import janitor
df.pivot_longer(
index = ['id', 'name', 'model_#'],
names_to = ('variable_x', 'variable_y'),
values_to = ['values_x', 'values_y'],
names_pattern = ['bp', 'rq'])
id name model_# variable_x values_x variable_y values_y
0 1 John 23984 bp1 23 rq1 252
1 2 John 23984 bp1 234 rq1 262
2 1 John 23984 bp2 252 rq2 234
3 2 John 23984 bp2 622 rq2 262