【问题标题】:Melt and Merge on Substring - Python & Pandas在子字符串上融合和合并 - Python & Pandas
【发布时间】:2018-01-22 12:13:58
【问题描述】:

我的数据有像

这样的数据
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)进行合并

【问题讨论】:

  • 你的问题很令人困惑,你能用输入和来自该输入的预期输出创建一个更简单的案例吗?
  • 你会原谅我的,但这是我能说的最简单的。我有很多分箱数据 bp1、bp2、bp3.... bp21,我已经将它们融合成一个带有融化的变量。我想对 rq1、rq2、rq3...rq21 做同样的事情,这样每一行都包含 bp1 rq1 value_x value_y。不是 bp1 rq2,因此我实际上想要合并两个融化的数据帧(rq 和 bp),但要沿着子字符串(1 到 1、2 到 2)。
  • 那么,cd1、sf1 和 sa1 列对您的结果没有任何影响吗?
  • 正确。这只是在将数据从其原始形式转换时必须考虑的一系列附加变量。
  • 很抱歉,如果我使用的随机数的差异在这方面造成了混淆。没有值变化,只是行和列操作。

标签: python pandas merge melt


【解决方案1】:

解决方案

设置索引...
使用聪明的专栏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

【讨论】:

  • 底部的输出正是我想要的(我试图通过只保留两个变量来缩短一点)。让我快速尝试一下。 Tyvm 为您提供帮助。/
  • 我正在做一些更简洁的事情。我应该在几分钟内得到它
  • @MaxU 我心里放不下这个。如果我没有得到满意的答案,那会困扰我一整天。而且我还有很多工作要做,所以我很幸运我找到了一个不错的答案(-:
  • @piRSquared,是的,这个看起来更优雅!
  • 感谢 piRSquared!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-22
  • 1970-01-01
  • 2021-02-22
  • 1970-01-01
  • 2016-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多