根据两列值将单行转换为两行

时间:2019-09-22 03:17:15

标签: python pandas

import pandas as pd
my_df = pd.DataFrame(columns=['b_code', 'c_code', 'name'], data = [[3401560221954, 6275442, 'name 1'], [987510, 987510, 'name 2'], [4473089, '', 'name 3'], ['', 9584362, 'name 4']])

以上数据框是一个样本集。我的数据框有70列。

如果两列“ b_code”和“ c_code”具有不同的值,我想将单行转换为两行。我正在寻找如下输出:

    b_code            c_code   name
0   3401560221954              name 1
1                     6275442  name 1
2        987510       987510   name 2
3        4473089               name 3
4                     9584362  name 4

3 个答案:

答案 0 :(得分:1)

如何将数据帧手动划分为要复制的部分和不复制的部分,然后再将所有内容重新连接在一起。

cond = (my_df.c_code != my_df.b_code) & (my_df.b_code != '') & (my_df.c_code != '')
repl1 = my_df[cond].copy()
repl1['b_code'] = ''
repl2 = my_df[cond].copy()
repl2['c_code'] = ''
pd.concat([my_df[~cond], repl1, repl2]).sort_index().reset_index(drop=True)


          b_code   c_code    name
0                 6275442  name 1
1  3401560221954           name 1
2         987510   987510  name 2
3        4473089           name 3
4                 9584362  name 4

这不能保证复制的行顺序。如果要保证顺序,可以更改其中一个副本的索引。因此,要获得与示例完全相同的顺序,可以在代码的最后一行之前为repl1执行此操作:

repl1.index = np.arange(len(repl1)) + 0.01

答案 1 :(得分:1)

您可以使用group by并申请实现此目的。在Apply功能中,您可以通过添加新行来检查条件并在条件匹配时拆分行



def split_row(x):
    x= x.copy()
    if (type(x.iloc[0].b_code) is int and type(x.iloc[0].c_code) is int) \
        and (x.iloc[0].b_code != x.iloc[0].c_code):
        new_row = x.copy()
        new_row.b_code=""
        x.c_code = ""
        x=x.append(new_row)

    return x


my_df.groupby(["b_code", "c_code"]).apply(split_row).reset_index(drop=True)

答案 2 :(得分:1)

Series.ne的重复行创建布尔掩码(不等于),然后使用concat将原始行和DataFrame.assign的行与更改后的代码一起过滤,并对索引进行100%正确排序,因为默认算法在DataFrame.sort_index中也是不稳定的quicksort

mask = my_df['c_code'].ne(my_df['b_code']) & my_df['b_code'].ne('') & my_df['c_code'].ne('')

备用mask

mask = my_df['c_code'].ne(my_df['b_code']) & my_df[['b_code','c_code']].eq('').sum(1).ne(1)

print (mask)
0     True
1    False
2    False
3    False
dtype: bool

df = my_df[mask]
print (df)
          b_code   c_code    name
0  3401560221954  6275442  name 1

df = pd.concat([df.assign(b_code = '').rename(lambda x: x + .3), 
                df.assign(c_code = '').rename(lambda x: x + .5),  
                my_df[~mask]]).sort_index().reset_index(drop=True)
print (df)
          b_code   c_code    name
0                 6275442  name 1
1  3401560221954           name 1
2         987510   987510  name 2
3        4473089           name 3
4                 9584362  name 4

如果重复行中的排序不重要:

df = pd.concat([df.assign(b_code = ''), 
                df.assign(c_code = ''),  
                my_df[~mask]]).sort_index().reset_index(drop=True)