Сравните значение ячейки первой строки в кадре данных со значением ячейки других строк

У меня есть datafarme, который имеет 50 столбцов и более 200 строк с двоичными значениями:

 
a1  a2  a3  a4  ….. a50
0   1   0   1   ….. 1
1   0   0   1   ….  0
0   1   1   0   ….  0
1   1   1   0   ….  1

Я хотел бы сравнить значения ячеек первой строки с другими строками одну за другой и создать 51-й столбец, который выводит несоответствующие ячейки, как показано ниже: (поскольку первая строка не сравнивается ни с одной строкой, она получит значение nan)

 
a51
NAN
a1,a2,…,a50
a3,a4…,a50
a1,a3,a4,…

Я не уверен, как это сделать эффективно. Я не нашел ответа, похожего на этот вопрос. Извините, если я задаю повторный вопрос. Заранее спасибо!

Всего 3 ответа


Вот один из подходов:

import numpy as np

a = df.to_numpy()
m = np.where(a[0,:] != a[1:,None], df.columns, np.nan)
pd.DataFrame(m.squeeze()).stack().groupby(level=0).agg(', '.join)

0    a1, a2, a50
1    a3, a4, a50
2     a1, a3, a4
dtype: object

Входные данные:

print(df)

   a1  a2  a3  a4  a50
0   0   1   0   1    1
1   1   0   0   1    0
2   0   1   1   0    0
3   1   1   1   0    1

Я предполагаю, что вы хотите список имен столбцов, которые не соответствуют первой строке:

df['a51'] = df.iloc[1:].apply(lambda row: df.columns[df.iloc[0] != row].values, axis=1)

200 строк достаточно малы, поэтому apply(..., axis=1) не является проблемой производительности.


Настроить

import numpy as np
df = pd.DataFrame(np.random.randint(2,size=(200,50)),
                  columns =[f'a{i}' for i in range(1,51)])

Series.dot + DataFrame.add_suffix и Series.str.rstrip

df['a51']=df.iloc[1:].ne(df.iloc[0]).dot(df.add_suffix(', ').columns).str.rstrip(', ')

Сравнение времени для 50 столбцов и 200 строк

%%timeit
df['a51'] = df.iloc[1:].ne(df.iloc[0]).dot(df.add_suffix(', ').columns).str.rstrip(', ')
25.4 ms ± 681 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)


%%timeit
a = df.to_numpy()
m = np.where(a[0,:] != a[1:,None], df.columns, np.nan)
pd.DataFrame(m.squeeze()).stack().groupby(level=0).agg(', '.join)
41.1 ms ± 4.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)


%%timeit
df.iloc[1:].apply(lambda row: df.columns[df.iloc[0] != row].values, axis=1)
147 ms ± 18.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Есть идеи?

10000