python panda通过删除重复项来连接动态列

时间:2017-06-05 16:52:32

标签: python performance pandas string-concatenation

我们有一个用例,我们需要通过删除duplicates来连接行中的所有列值.Data存储在panda的数据框中。 例如,考虑下面的数据帧df,列A,B,C

A   B   C   
X1  AX  X1
X2  X2  X1
X3  X3  X3
X4  XX  XX

我想添加一个新列,它将A到B连接到C,如果通过保留订单找到重复项,则删除重复项。输出就像

A   B   C   Newcol

X1  AX  X1  X1_AX
X2  X2  X1  X2_X1
X3  X3  X3  X3
X4  XX  XX  X4_XX

请注意,列数是动态的。 截至目前,我正在使用命令

df.apply(lambda x: '-'.join(x.dropna().astype(str).drop_duplicates()),axis=1)

但这非常慢,我的数据大约需要150秒。 但由于90%的数据框通常只有2列,我在我的代码中放了一个if语句,并为2列的情况运行以下命令

t1=pd.Series(np.where(df.iloc[:,0].dropna().astype(str) != df.iloc[:,1].dropna().astype(str), df.iloc[:,0].dropna().astype(str)+"-"+df.iloc[:,1].dropna().astype(str),df.iloc[:,1].dropna().astype(str)))

需要大约55.3毫秒

甚至

t1=df.iloc[:,0].dropna().astype(str).where(df.iloc[:,0].dropna().astype(str) == df.iloc[:,1].dropna().astype(str), df.iloc[:,0].dropna().astype(str)+"-"+df.iloc[:,1].dropna().astype(str))

两者消耗几乎相同的时间(55毫秒而不是150秒),但问题是它仅适用于2列。 我想创建一个通用语句,以便它可以处理n个列。 我尝试在顶部使用reduce,但是当我尝试使用3列时它出错了。

reduce((lambda x,y:pd.Series(np.where(df.iloc[:,x].dropna().astype(str) != df.iloc[:,y].dropna().astype(str), df.iloc[:,x].dropna().astype(str)+"-"+df.iloc[:,y].dropna().astype(str),df.iloc[:,y].dropna().astype(str)))),list(range(df.shape[1])))
  

TypeError:'>''在'str'和'int'

的实例之间不受支持

请注意,df实际上是多核并行任务的一部分。如果这些建议排除了并行性,那将会很棒。

2 个答案:

答案 0 :(得分:3)

尝试

df['new'] = df.astype('str').apply(lambda x: '_'.join(set(x)), axis = 1)

    A   B   C   new
0   X1  AX  X1  AX_X1
1   X2  X2  X1  X1_X2
2   X3  X3  X3  X3
3   X4  XX  XX  X4_XX

编辑:维护列值的顺序

def my_append(x):
    l = []
    for elm in x:
        if elm not in l:
            l.append(elm)
    return '_'.join(l)


df['New col']=df.astype('str').apply(my_append, axis = 1)

1000 loops, best of 3: 871 µs per loop

返回

    A   B   C   New col
0   X1  AX  X1  X1_AX
1   X2  X2  X1  X2_X1
2   X3  X3  X3  X3
3   X4  XX  XX  X4_XX

编辑1:如果您在任何列中都有像这样的

    A   B   C
0   X1  AX  X1
1   X2  X2  X1
2   X3  X3  X3
3   NaN XX  XX

处理该函数,然后应用

def my_append(x):
l = []
for elm in x:
    if elm not in l:
        l.append(elm)
l = [x for x in l if str(x) != 'nan']
return '_'.join(l)

df['New col']=df.astype('str').apply(my_append, axis = 1)


    A   B   C   New col
0   X1  AX  X1  X1_AX
1   X2  X2  X1  X2_X1
2   X3  X3  X3  X3
3   NaN XX  XX  XX

答案 1 :(得分:1)

pd.unique没有排序。使用它包含在理解

df.assign(new_col=['_'.join(pd.unique(row)) for row in df.values])

    A   B   C new_col
0  X1  AX  X1   X1_AX
1  X2  X2  X1   X2_X1
2  X3  X3  X3      X3
3  X4  XX  XX   X4_XX

处理NaN

df.assing(new_col=[
        '_'.join(pd.unique([i for i in row if pd.notnull(i)])) for row in df.values
    ])