Я хочу рассчитать среднее значение (т.е. Numpy.mean) и sem (т.е. scipy.stats.sem) уникальных значений float в каждой строке pandas DataFrame в векторном виде.
Пример ввода:
import pandas as pd
t = pd.DataFrame(data={'c1':[1.,2.,3.,4.],
'c2':[1.,2.,3.,3.],
'c3':[1.,2.,2.,2.],
'c4':[1.,1.,1.,1.]})
t.index.name = 'i'
# unique values: [1] [1,2] [1,2,3] [1,2,3,4]
Ожидаемый результат:
mean sem
i
0 1.0 NaN
1 1.5 0.500000
2 2.0 0.577350
3 2.5 0.645497
Пожалуйста, не отправляйте не векторизованные решения вроде этого:
import numpy as np, scipy.stats as ss
def fun(x):
r = x.transpose()[x.index[0]].value_counts(sort=False).rename('count')
r.index.name = 'value'
y = r.index.values
return pd.DataFrame({'mean':np.mean(y), 'sem':ss.sem(y)}, index=[0])
t2 = t.groupby(t.index.names).apply(fun)
t2.index = t2.index.droplevel(1)
Реальный DataFrame имеет> 1e12 строк, поэтому неэффективные решения не будут делать.
В идеале было бы здорово иметь условие уникальности (т.е. абс. Разность или отклонение отношения от одного) от значений float, но любое эффективное решение было бы удивительным.
Спасибо за помощь!
IIUC, pandas
имеют sem
, вам не нужно вызывать scipy
newdf=pd.DataFrame(list(map(set,t.values)))
newdf.T.agg(['mean','sem']).T
Out[436]:
mean sem
0 1.0 NaN
1 1.5 0.500000
2 2.0 0.577350
3 2.5 0.645497
Вот почти векторизованное решение, единственная не-векторизованная операция создает вашу маску, которая в основном векторизована, но вам нужно создать один за столбец.
m = np.column_stack([t[col].duplicated() for col in t])
out = t.mask(m)
pd.DataFrame({'mean': np.mean(out), 'sem':ss.sem(out, nan_policy='omit').data})
mean sem
c1 2.5 0.645497
c2 2.0 0.577350
c3 1.5 0.500000
c4 1.0 0.000000
У меня недостаточно памяти, чтобы проверить это на вашем размере DataFrame, но вот образец на 1-миллионной строке DataFrame:
t = pd.concat([t]*250000)
In [649]: %%timeit
...: m = np.column_stack([t[col].duplicated() for col in t])
...: out = t.mask(m)
...: pd.DataFrame({'mean': np.mean(out), 'sem':ss.sem(out, nan_policy='omit').data})
...:
326 ms ± 10.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
pandas.Series.value_counts
,pandas.Series.unique
,pandas.core.groupby.SeriesGroupBy.unique
,pandas.unique
и т. Д. Вопрос заключается в том, существует ли способ эффективного объединения таких функций. Я полагаю, что решение транспонировало бы входной DataFrame таким образом, чтобы строки становились столбцами, а затем применяли одну из функций уникальности к столбцам Series. Обратите внимание, что настоящий DataFrame имеет MultiIndex, поэтому при его выполнении необходимо соблюдать осторожность.