Я пытаюсь найти имена столбцов каждого столбца в кадре данных Pandas, где значение больше, чем у другого столбца.

Например, если у меня есть следующий фрейм данных:

   A  B  C  D  threshold
0  1  3  3  1  2
1  2  3  6  1  5
2  9  5  0  2  4

Для каждой строки я хотел бы вернуть имена столбцов, значения которых превышают пороговое значение, поэтому я бы хотел:

0: B, C
1: C
2: A, B

Любая помощь приветствуется!

5
FClubb 29 Авг 2017 в 12:15

3 ответа

Лучший ответ

Если вы хотите значительно увеличить скорость, вы можете использовать векторизованную функцию where NumPy.

s = np.where(df.gt(df['threshold'],0), ['A, ', 'B, ', 'C, ', 'D, ', ''], '')
pd.Series([''.join(x).strip(', ') for x in s])

0    B, C
1       C
2    A, B
dtype: object

Существует более чем на порядок ускорение по сравнению с решениями @jezrael и MaxU при использовании кадра данных из 100 000 строк. Здесь я сначала создаю тестовый DataFrame.

n = 100000
df = pd.DataFrame(np.random.randint(0, 10, (n, 5)), 
                  columns=['A', 'B', 'C', 'D', 'threshold'])

Задержки

%%timeit
>>> s = np.where(df.gt(df['threshold'],0), ['A, ', 'B, ', 'C, ', 'D, ', ''], '')
>>> pd.Series([''.join(x).strip(', ') for x in s])
280 ms ± 5.29 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
>>> df1 = df.drop('threshold', 1).gt(df['threshold'], 0)
>>> df1 = df1.apply(lambda x: ', '.join(x.index[x]),axis=1)
3.15 s ± 82.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
>>> x = df.drop('threshold',1)
>>> x.T.gt(df['threshold']).agg(lambda c: ', '.join(x.columns[c]))
3.28 s ± 145 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
4
Ted Petrou 29 Авг 2017 в 17:32

Вы можете сделать это следующим образом:

In [99]: x = df.drop('threshold',1)

In [100]: x
Out[100]:
   A  B  C  D
0  1  3  3  1
1  2  3  6  1
2  9  5  0  2

In [102]: x.T.gt(df['threshold']).agg(lambda c: ', '.join(x.columns[c]))
Out[102]:
0    B, C
1       C
2    A, B
dtype: object
2
MaxU 29 Авг 2017 в 09:35

Вы можете использовать:

df1 = df.drop('threshold', 1).gt(df['threshold'], 0)
df1 = df1.apply(lambda x: ', '.join(x.index[x]),axis=1)
print (df1)
0    B, C
1       C
2    A, B
dtype: object

Аналогичное решение:

df1 = df.drop('threshold', 1).gt(df['threshold'], 0).stack().rename_axis(('a','b'))
        .reset_index(name='boolean')
a = df1[df1['boolean']].groupby('a')['b'].apply(', '.join).reset_index()
print (a)
   a     b
0  0  B, C
1  1     C
2  2  A, B
5
jezrael 29 Авг 2017 в 09:29