熊猫:根据列值扩展行

时间:2020-08-27 23:16:37

标签: python python-3.x pandas numpy loops

我有一个列表数据集列表:

data_set = [['note_a', 'mix'],['note_b', 'mix'], ['mix','leave','note_a','note_b','random'],['mix','random','note_a','note_b']]

我正在使用它的笛卡尔积:

import itertools
all_method = pd.DataFrame(itertools.product(*data_set))
all_method

输出

         0       1       2       3
0   note_a  note_b     mix     mix
1   note_a  note_b     mix  random
2   note_a  note_b     mix  note_a
3   note_a  note_b     mix  note_b
4   note_a  note_b   leave     mix
..     ...     ...     ...     ...
75     mix     mix  note_b  note_b
76     mix     mix  random     mix
77     mix     mix  random  random
78     mix     mix  random  note_a
79     mix     mix  random  note_b

[80 rows x 4 columns]

现在我想用三个新值扩展每个混合值:

mix = ['copy_a', 'copy_b', 'copy_c']

因此,如果连续存在混合,则应扩展三行,并用每个值替换混合。

我要看的三行示例:

[('note_a', 'note_b', 'copy_a', 'copy_a'), ('note_a', 'note_b', 'copy_b', 'copy_b'), ('note_a', 'note_b', 'copy_c','copy_c'),
 ('note_a', 'note_b', 'copy_a', 'random'), ('note_a', 'note_b', 'copy_b', 'random'), ('note_a', 'note_b', 'copy_c', 'random'),
 ('note_a', 'note_b', 'copy_a', 'note_a'), ('note_a', 'note_b', 'copy_b', 'note_a'), ('note_a', 'note_b', 'copy_c', 'note_a')]

在第一行中,有两个“ mix”,因此它扩展了三行,其中“ copy_a”填充为“ mix”,然后是“ copy_b”填充为“ mix”,最后是“ copy_c”填充为“ mix”。

我尝试过的:

import itertools
all_method = list(itertools.product(*data_set))
all_method


def extend_rows_func(data):
    extend_rows = []
    mix         = ['copy_a', 'copy_b', 'copy_c']
    for i in data:
        if 'mix' in i:
            for copy_op in mix: 
                extend_rows.append([copy_op if x== 'mix' else x for x in i])
        else:
            extend_rows.append(list(i))
    return extend_rows

是否有任何优化的方法或熊猫方法而不使用三个循环?

2 个答案:

答案 0 :(得分:1)

您可以先考虑replace然后考虑concat

pd.concat(all_method.replace('mix',copy) for copy in ['copy_a', 'copy_b', 'copy_c'])

输出:

         0       1       2       3
0   note_a  note_b  copy_a  copy_a
1   note_a  note_b  copy_a  random
2   note_a  note_b  copy_a  note_a
3   note_a  note_b  copy_a  note_b
4   note_a  note_b   leave  copy_a
..     ...     ...     ...     ...
75  copy_c  copy_c  note_b  note_b
76  copy_c  copy_c  random  copy_c
77  copy_c  copy_c  random  random
78  copy_c  copy_c  random  note_a
79  copy_c  copy_c  random  note_b

[240 rows x 4 columns]

如果要将原始行排列在一起,可以将其与sort_index()链接起来:

(pd.concat(all_method.replace('mix',copy) 
               for copy in ['copy_a', 'copy_b', 'copy_c'])
   .sort_index()
)

输出:

         0       1       2       3
0   note_a  note_b  copy_a  copy_a
0   note_a  note_b  copy_b  copy_b
0   note_a  note_b  copy_c  copy_c
1   note_a  note_b  copy_a  random
1   note_a  note_b  copy_b  random
..     ...     ...     ...     ...
78  copy_a  copy_a  random  note_a
78  copy_b  copy_b  random  note_a
79  copy_b  copy_b  random  note_b
79  copy_a  copy_a  random  note_b
79  copy_c  copy_c  random  note_b

[240 rows x 4 columns]

答案 1 :(得分:0)

请注意,此方法需要一些时间才能运行

mid=all_method.replace('mix',','.join(['copy_a', 'copy_b', 'copy_c'])).applymap(lambda x: x.split(','))

def unnesting_cell(df):

        explode = df.columns[df.iloc[0].str.len()>1]
        if len(explode) == 0 :
            return df
        else:
            df1 = pd.concat([
                pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)
            df1.index=df.index.tolist()*len(df1)
            return df1.join(df.drop(explode, 1).apply(lambda x : x.str[0] , axis=1), how='left')

df = pd.concat([unnesting_cell(mid.loc[[x]]) for x in mid.index])