У меня есть 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)