Вы можете воспользоваться функцией apply
на pd.DataFrame
. Это позволяет применять произвольные функции к столбцам или строкам DataFrame
. Используя ваш пример:
df = pd.DataFrame([[20, 10], [60, 25], [50, 15]])
Для создания таблиц сопряженности можно использовать lambda
и некоторые векторные операции
>>> members = np.array([70, 30])
>>> df.apply(lambda x: np.array([x, members-x]), axis=1)
0 [[20, 10], [50, 20]]
1 [[60, 25], [10, 5]]
2 [[50, 15], [20, 15]]
И это, конечно, можно обернуть функцией scipy
.
df.apply(lambda x: chi2_contingency(np.array([x, members-x])), axis=1)
Это производит все возможные возвращаемые значения, но, разрезая выходные данные, можно указать желаемые возвращаемые значения, оставив, например, ожидаемые массивы. Полученный ряд также можно преобразовать в DataFrame
.
>>> s = df.apply(lambda x: chi2_contingency(np.array([x, members-x]))[:-1], axis=1)
>>> s
0 (0.056689342403628114, 0.8118072280034329, 1)
1 (0.0, 1.0, 1)
2 (3.349031920460492, 0.06724454934343391, 1)
dtype: object
>>> s.apply(pd.Series)
0 1 2
0 0.056689 0.811807 1.0
1 0.000000 1.000000 1.0
2 3.349032 0.067245 1.0
Сейчас я не знаю об эффективности выполнения этого подхода, но я бы доверял тем, кто реализовал эти функции. И, скорее всего, скорость не так критична. Но он по крайней мере эффективен в том смысле, что его (гипотетически) легко понять и быстро написать.