Как {pivot | денормализовать | манипулировать} таблицей CSV в Python - PullRequest
0 голосов
/ 27 июня 2018

Извините за грязный заголовок, я не знал, как правильно сформулировать этот вопрос.

Допустим, у меня есть таблица, в которой первые три столбца - это foo bar и baz. Тогда есть некоторое количество произвольных столбцов после. Я хочу манипулировать таблицей так, чтобы все эти произвольные столбцы были свернуты в столбце on, называемом num.

Пример проясняет ситуацию

foo, bar, baz, 100, 101, 102, 103, 104,
1,   1,   1,  10,  11,  12,  13,  14,
1,   1,   2,  15,  16,  17,  18,  19,
1,   2,   1,  20,  21,  22,  23,  24,

Этот вход должен транспонироваться в:

num, foo, bar, baz, value,
100,   1,    1,  1,    10,
100,   1,    1,  2,    15,
100,   1,    2,  1,    20,
101,   1,    1,  1,    11,
101,   1,    1,  2,    16,
101,   1,    2,  1,    21,
102,   1,    1,  1,    12,
102,   1,    1,  2,    17,
102,   1,    2,  1,    22,
...

Я написал собственное решение Python, которое делает это. Это было не сложно, но я чувствую, что изобретаю колесо заново.

Есть ли способ сделать это с помощью библиотеки, такой как pandas или каким-нибудь другим модулем управления таблицами?

Ответы [ 4 ]

0 голосов
/ 27 июня 2018

Как уже упоминалось выше, pandas.melt - лучший способ сделать это!

import pandas as pd
import numpy as np

#Create the dataframe
df = pd.DataFrame({'foo' : np.random.randint(low = 0, high=5, size = 3), 'bar' : 
                  np.random.randint(low = 0, high=5, size = 3),'baz' : 
                  np.random.randint(low = 0, high=5, size = 3)})

for i in range(100,105):
df['%d'%i] = np.random.randint(low = 10, high=20, size = 3)

print(df) 
   foo  bar  baz  100  101  102  103  104
0    2    1    4   16   14   13   16   11
1    3    0    4   11   17   12   15   18
2    4    1    1   13   15   11   18   17

А теперь основная функция:

pd.melt(frame=df, id_vars= ['foo', 'bar', 'baz'], value_vars= ['%d'%i for i in 
range(100,105)])

#output
   foo  bar baz variable  value
0   2   1   4   100        16
1   3   0   4   100        11
2   4   1   1   100        13
3   2   1   4   101        14
4   3   0   4   101        17
5   4   1   1   101        15
6   2   1   4   102        13
7   3   0   4   102        12
8   4   1   1   102        11
9   2   1   4   103        16
10  3   0   4   103        15
11  4   1   1   103        18
12  2   1   4   104        11
13  3   0   4   104        18
14  4   1   1   104        17
0 голосов
/ 27 июня 2018

Вы можете использовать изменение формы данных с set_index, stack и переименование некоторых столбцов:

(df.set_index(['foo','bar','baz'])
   .stack()
   .reset_index(name='value')
   .rename(columns={'level_3':'num'}))

Выход:

    foo  bar  baz  num  value
0     1    1    1  100     10
1     1    1    1  101     11
2     1    1    1  102     12
3     1    1    1  103     13
4     1    1    1  104     14
5     1    1    2  100     15
6     1    1    2  101     16
7     1    1    2  102     17
8     1    1    2  103     18
9     1    1    2  104     19
10    1    2    1  100     20
11    1    2    1  101     21
12    1    2    1  102     22
13    1    2    1  103     23
14    1    2    1  104     24
0 голосов
/ 27 июня 2018

Использование pandas.melt:

res = pd.melt(df, id_vars=['foo', 'bar', 'baz'])

print(res)

    foo  bar  baz variable  value
0     1    1    1      100     10
1     1    1    2      100     15
2     1    2    1      100     20
3     1    1    1      101     11
4     1    1    2      101     16
5     1    2    1      101     21
6     1    1    1      102     12
7     1    1    2      102     17
8     1    2    1      102     22
9     1    1    1      103     13
10    1    1    2      103     18
11    1    2    1      103     23
12    1    1    1      104     14
13    1    1    2      104     19
14    1    2    1      104     24
0 голосов
/ 27 июня 2018
cols = np.concatenate([['num'], df.columns[:3], ['value']])
pd.DataFrame([
    [a, b, c, d, e]
    for b, c, d, *x in df.values
    for a, e in zip(df.columns[3:], x)
]).set_axis(cols, axis=1, inplace=False).sort_values('num')

    num  foo  bar  baz  value
0   100    1    1    1     10
5   100    1    1    2     15
10  100    1    2    1     20
1   101    1    1    1     11
6   101    1    1    2     16
11  101    1    2    1     21
2   102    1    1    1     12
7   102    1    1    2     17
12  102    1    2    1     22
3   103    1    1    1     13
8   103    1    1    2     18
13  103    1    2    1     23
4   104    1    1    1     14
9   104    1    1    2     19
14  104    1    2    1     24
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...