Использование:
df = pd.DataFrame({
'A':[5,20],
'B':[10,25],
'C':[15,30]
})
print (df)
A B C
0 5 10 15
1 20 25 30
Сначала получите все комбинации столбцов в 2 списках (a
для первого значения кортежей, b
для второго):
from itertools import combinations
a, b = zip(*(combinations(df.columns, 2)))
Затем используйте DataFrame.loc
для повторяющихся столбцов списками:
df1 = df.loc[:, a]
print (df1)
A A B
0 5 5 10
1 20 20 25
df2 = df.loc[:, b]
print (df2)
B C C
0 10 15 15
1 25 30 30
Преобразование значений в пустые массивы для окончательного DataFrame и получение новых имен столбцов по списку:
c = [f'{x}_{y}' for x, y in zip(a, b)]
arr1 = df1.values
arr2 = df2.values
df = pd.DataFrame((arr1-arr2)/(arr1+arr2), columns=c)
print (df)
A_B A_C B_C
0 -0.333333 -0.5 -0.200000
1 -0.111111 -0.2 -0.090909
Другое решение очень похоже, только создать комбинацию по arange
по длине столбцов, а имена последних новых столбцов создаются путем индексации:
from itertools import combinations
a, b = zip(*(combinations(np.arange(len(df.columns)), 2)))
arr = df.values
cols = df.columns.values
arr1 = arr[:, a]
arr2 = arr[:, b]
c = [f'{x}_{y}' for x, y in zip(cols[np.array(a)], cols[np.array(b)])]
df = pd.DataFrame((arr1-arr2)/(arr1+arr2), columns=c)
Производительность
Проверено в 5 строках и 381 столбце:
np.random.seed(2019)
df = pd.DataFrame(np.random.randint(10,100,(5,381)))
df.columns = ['c'+str(i+1) for i in range(df.shape[1])]
#print (df)
In [4]: %%timeit
...: a, b = zip(*(combinations(np.arange(len(df.columns)), 2)))
...: arr = df.values
...: cols = df.columns.values
...: arr1 = arr[:, a]
...: arr2 = arr[:, b]
...: c = [f'{x}_{y}' for x, y in zip(cols[np.array(a)], cols[np.array(b)])]
...: pd.DataFrame((arr1-arr2)/(arr1+arr2), columns=c)
...:
62 ms ± 7.29 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [5]: %%timeit
...: a, b = zip(*(combinations(df.columns, 2)))
...: df1 = df.loc[:, a]
...: df2 = df.loc[:, b]
...: arr1 = df1.values
...: arr2 = df2.values
...: c = [f'{x}_{y}' for x, y in zip(a, b)]
...: pd.DataFrame((arr1-arr2)/(arr1+arr2), columns=c)
...:
63.2 ms ± 253 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [7]: %%timeit
...: func1(df)
...:
89.2 ms ± 331 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [8]: %%timeit
...: a, b = zip(*(combinations(df.columns, 2)))
...: df1 = df.loc[:, a]
...: df2 = df.loc[:, b]
...: c = [f'{x}_{y}' for x, y in zip(a, b)]
...: pd.DataFrame((df1.values-df2.values)/(df1.values+df2.values), columns=c)
...:
69.8 ms ± 6.04 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)