在 Python 中扩展下划线分隔的元组的好方法

Excellent way of expanding tuple separated by underscore in Python

给定一个包含两个变量的元组 ('a','E1_g1'),我想将其扩展为包含三个变量的元组 ('a','E1', 'g1')

下面的代码应该回答 objective

import numpy as np
import pandas as pd
np.random.seed(0)
arr = np.random.randint(5, size=(2, 9))

_names = ['a','a','a','a','a','a','a','a','a']
_idx = ['E1_g1','E1_g2','E1_g3',
        'E2_g1','E2_g2','E2_g3',
        'E3_g1','E3_g2','E3_g3']
columns = pd.MultiIndex.from_arrays([_names, _idx])

df= pd.DataFrame(data=arr, columns=columns)

ntuple=[]
for dg in df.columns:
    A,B=dg
    f,r=B.split('_')
    ntuple.append((A,f,r))

# df.colums=pd.MultiIndex.from_arrays(ntuple) # WIP since I still got an error here

但是,我想知道是否还有另一种方法,也许可以改进,尤其是 for-loops 中的步骤。

你可以试试这个,

new_list = [tuple([_names[i]] + _idx[i].split("_")) for i in range(len(_idx))]

输出-

[('a', 'E1', 'g1'),
 ('a', 'E1', 'g2'),
 ('a', 'E1', 'g3'),
 ('a', 'E2', 'g1'),
 ('a', 'E2', 'g2'),
 ('a', 'E2', 'g3'),
 ('a', 'E3', 'g1'),
 ('a', 'E3', 'g2'),
 ('a', 'E3', 'g3')]

不是最干净的,但这是我能够做到的:

idx = df.columns.to_flat_index()
pd.MultiIndex.from_tuples(map(tuple, idx.str.join("_").str.split("_")))

输出:

MultiIndex([('a', 'E1', 'g1'),
            ('a', 'E1', 'g2'),
            ('a', 'E1', 'g3'),
            ('a', 'E2', 'g1'),
            ('a', 'E2', 'g2'),
            ('a', 'E2', 'g3'),
            ('a', 'E3', 'g1'),
            ('a', 'E3', 'g2'),
            ('a', 'E3', 'g3')],
           )

但是,由于 dtype 是对象,您真的不能再快了。其实通俗理解会快一点:

n = len(df.columns)
lvl_0, lvl_1 = df.columns.levels

[(a, b, c) for a, (b, c) in zip(*lvl_0*n, lvl_1.str.split("_"))]

性能:

In [4]: %timeit pd.MultiIndex.from_tuples(map(tuple, idx.str.join("_").str.split("_")))
914 µs ± 60.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [5]: %timeit pd.MultiIndex.from_tuples([(a, b, c) for a, (b, c) in zip(*lvl_0*n, lvl_1.str.split("_"))])
877 µs ± 53.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

唯一真正的好处是第一个示例中的语法相对简单。