it-swarm.com.ru

Рассчитать среднее значение для каждой x строк в таблице и создать новую таблицу

У меня есть длинная таблица данных (~ 200 строк на 50 столбцов), и мне нужно создать код, который может вычислять средние значения для каждых двух строк и для каждого столбца в таблице с окончательным выводом, являющимся новой таблицей среднего ценности. Это очевидно безумие, чтобы сделать в Excel! Я использую python3, и мне известны некоторые похожие вопросы: здесь , здесь и здесь . Но ничего из этого не помогает, так как мне нужен элегантный код для работы с несколькими столбцами и создания организованной таблицы данных. Кстати, мой исходный источник данных был импортирован с помощью pandas и ​​определен как фрейм данных, но не смог найти простой способ сделать это в pandas. Помощь очень ценится.

Пример таблицы (краткая версия):

a   b   c   d
2   50  25  26
4   11  38  44
6   33  16  25
8   37  27  25
10  28  48  32
12  47  35  45
14  8   16  7
16  12  16  30
18  22  39  29
20  9   15  47

Ожидаемая средняя таблица:

a    b     c     d
3   30.5  31.5  35
7   35    21.5  25
11  37.5  41.5  38.5
15  10    16    18.5
19  15.5  27    38
13
Gnu

Вы можете создать искусственную группу, используя df.index//2 (или, как указал @DSM, используя np.arange(len(df))//2, чтобы она работала для всех индексов), а затем использовать groupby:

df.groupby(np.arange(len(df))//2).mean()
Out[13]: 
      a     b     c     d
0   3.0  30.5  31.5  35.0
1   7.0  35.0  21.5  25.0
2  11.0  37.5  41.5  38.5
3  15.0  10.0  16.0  18.5
4  19.0  15.5  27.0  38.0
18
ayhan

NumPythonic мог бы извлечь элементы в виде массива NumPy с помощью df.values, затем преобразовать его в массив 3D с элементами 2 вдоль axis=1 и 4 вдоль axis=2 и выполнить среднее сокращение по axis=1 и, наконец, преобразовать обратно в фрейм данных, например так -

pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))

Оказывается, вы можете представить очень эффективный инструмент NumPy: np.einsum , чтобы сделать это average-reduction как комбинацию sum-reduction и scaling-down, вот так -

pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)

Обратите внимание, что предлагаемые подходы предполагают, что количество строк делится на 2

Также как noted by @DSM , чтобы сохранить имена столбцов, вам нужно добавить columns=df.columns при преобразовании обратно в Dataframe, т.е.

pd.DataFrame(...,columns=df.columns)

Пробный прогон -

>>> df
    0   1   2   3
0   2  50  25  26
1   4  11  38  44
2   6  33  16  25
3   8  37  27  25
4  10  28  48  32
5  12  47  35  45
6  14   8  16   7
7  16  12  16  30
8  18  22  39  29
9  20   9  15  47
>>> pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))
    0     1     2     3
0   3  30.5  31.5  35.0
1   7  35.0  21.5  25.0
2  11  37.5  41.5  38.5
3  15  10.0  16.0  18.5
4  19  15.5  27.0  38.0
>>> pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)
    0     1     2     3
0   3  30.5  31.5  35.0
1   7  35.0  21.5  25.0
2  11  37.5  41.5  38.5
3  15  10.0  16.0  18.5
4  19  15.5  27.0  38.0

Испытания во время выполнения -

В этом разделе давайте протестируем все три подхода, перечисленных до сих пор, чтобы решить проблему производительности, включая @ayhan's solution with groupby .

In [24]: A = np.random.randint(0,9,(200,50))

In [25]: df = pd.DataFrame(A)

In [26]: %timeit df.groupby(df.index//2).mean() # @ayhan's solution
1000 loops, best of 3: 1.61 ms per loop

In [27]: %timeit pd.DataFrame(df.values.reshape(-1,2,df.shape[1]).mean(1))
1000 loops, best of 3: 317 µs per loop

In [28]: %timeit pd.DataFrame(np.einsum('ijk->ik',df.values.reshape(-1,2,df.shape[1]))/2.0)
1000 loops, best of 3: 266 µs per loop
6
Divakar
df.set_index(np.arange(len(df)) // 2).mean(level=0)
4
piRSquared

Вы можете решить эту проблему, используя pd.rolling(), чтобы создать скользящее среднее, а затем просто захватить каждый второй элемент, используя iloc 

df = df.rolling(2).mean() 
df = df.iloc[::2, :]

Обратите внимание, что первое наблюдение будет отсутствовать (то есть прокатка начинается сверху) 

1
seeiespi