熊猫爆炸并丢弃多列重复项

时间:2020-02-10 14:12:28

标签: python pandas

尝试在多(4)列上执行explode时遇到一些问题。第一个问题是,如果我尝试一次爆炸所有列,则会遇到MemoryError。分别展开每个列之后,有很多重复项,因此我可以使用drop_duplicates(),但是由于列中有lists,因此会引发TypeError: unhashable type: 'list'。如果我使用astype(str)将列转换为字符串,则这些列不能与.explode()一起使用。因此,如果我在执行第二个pd.eval()之前尝试.explode()列,则会得到UndefinedVariableError: name 'nan' is not defined。这是示例数据集:

    id     col_1      col_2   col_3   col_4 
0    1 ['a','b']        nan   ['c']     nan   
1    2       nan  ['d','e']     nan     nan
2    3     ['f']        nan     nan     nan
3    4       nan      ['g']     nan     nan 
4    5       nan        nan   ['h']     nan
5    6       nan        nan   ['i']   ['j'] 

这是当前代码:

for i in new_table:
    new_table = new_table.explode(i)
    new_table = new_table.astype(str)
    new_table = new_table.drop_duplicates()
    new_table['col_1'] = pd.eval(new_table['col_1'])
    new_table['col_2'] = pd.eval(new_table['col_2'])
    new_table['col_3'] = pd.eval(new_table['col_3'])
    new_table['col_4'] = pd.eval(new_table['col_4'])

pd.eval()引发UndefiniedVariableError: name 'nan' is not defined。如果删除最后4行,则这些列将被解释为字符串,并且在第二个循环中,explode()不会执行任何操作,因为输入是字符串,而不是列表。但是,我必须(?)将列转换为字符串以执行drop_duplicates()

用于重新创建示例数据集的代码:

new_table = pd.DataFrame({'id':[1,2,3,4,5,6],
                          'col_1':[['a','b'],np.nan,['f'],np.nan,np.nan,np.nan],
                          'col_2':[np.nan,['d','e'],np.nan,['g'],np.nan,np.nan],
                          'col_3':[['c'],np.nan,np.nan,np.nan,['h'],['i']],
                          'col_4':[np.nan,np.nan,np.nan,np.nan,np.nan,['j']]})

预期输出:

id     col_1      col_2   col_3   col_4 
1          a        nan       c     nan
1          b        nan       c     nan
2        nan          d     nan     nan
2        nan          e     nan     nan
3          f        nan     nan     nan
4        nan          g     nan     nan
5        nan        nan       h     nan
6        nan        nan       i       j

2 个答案:

答案 0 :(得分:2)

你能这样吗?

class PasswordResetSerializer(PasswordResetSerializer):

    def get_email_options(self):
        request = self.context.get('request')
        domain = request.get_host()
        return {
            'subject_template_name': 'account/email/password_reset_key_subject.txt',
            'email_template_name': 'account/email/password_reset_key.txt',
            'extra_email_context': {'parsed_domain': domain},
            'html_email_template_name': 'account/password_reset_key.html',
        }

输出:

df[['id']].join((df[i].explode() for i in df.iloc[:,1:]))

请注意,我认为您正在做的事情和我正在做的事情的主要区别在于,您在数据帧上使用| | id | col_1 | col_2 | col_3 | col_4 | |---:|-----:|:--------|:--------|:--------|:--------| | 0 | 1 | a | nan | c | nan | | 0 | 1 | b | nan | c | nan | | 1 | 2 | nan | d | nan | nan | | 1 | 2 | nan | e | nan | nan | | 2 | 3 | f | nan | nan | nan | | 3 | 4 | nan | g | nan | nan | | 4 | 5 | nan | nan | h | nan | | 5 | 6 | nan | nan | i | j | ,因此,您要调用的每一列的数据帧都是重复的。然后,您仅选择“爆炸”列a并加入新的数据框。

我正在做的是爆炸每个列(pd.Series),并将每个“爆炸”系列的结果连接到索引上。我没有创建一堆在数据框上使用explode时创建的额外列。

答案 1 :(得分:2)

我有另一种使用new MyClass(serializedData)的方法,然后是stackexplode()cumcount,我认为您可以尝试一下。

unstack

s= new_table.set_index('id').stack(dropna=True).explode().to_frame('s')
final = (s.set_index(s.groupby(s.index.get_level_values(-1))
                              .cumcount(),append=True)['s'].unstack(1))
final = final.groupby(level=0).apply(lambda x: 
                      x.ffill().bfill()).drop_duplicates().droplevel(1)