在 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)
唯一真正的好处是第一个示例中的语法相对简单。
给定一个包含两个变量的元组 ('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)
唯一真正的好处是第一个示例中的语法相对简单。