Python, pandas фрейм данных, группировка по столбцу и заранее известные значения - PullRequest
0 голосов
/ 16 июня 2020

Рассмотрим этот пример:

>>> import pandas as pd
>>> df = pd.DataFrame(
...     [
...         ['X', 'R', 1],
...         ['X', 'G', 2],
...         ['X', 'R', 1],
...         ['X', 'B', 3],
...         ['X', 'R', 2],
...         ['X', 'B', 2],
...         ['X', 'G', 1],
...     ],
...     columns=['client', 'status', 'cnt']
... )
>>> df
  client status  cnt
0      X      R    1
1      X      G    2
2      X      R    1
3      X      B    3
4      X      R    2
5      X      B    2
6      X      G    1
>>>
>>> df_gb = df.groupby(['client', 'status']).cnt.sum().unstack()
>>> df_gb
status  B  G  R
client
X       5  3  4
>>>
>>> def color(row):
...     if 'R' in row:
...         red = row['R']
...     else:
...         red = 0
...     if 'B' in row:
...         blue = row['B']
...     else:
...         blue = 0
...     if 'G' in row:
...         green = row['G']
...     else:
...         green = 0
...     if red > 0:
...         return 'red'
...     elif blue > 0 and (red + green) == 0:
...         return 'blue'
...     elif green > 0 and (red + blue) == 0:
...         return 'green'
...     else:
...         return 'orange'
...
>>> df_gb.apply(color, axis=1)
client
X    red
dtype: object
>>>  

Этот код делает группировку по каждой категории (красный, зеленый, синий). Затем apply используется для реализации logi c для определения цвета каждого клиента (в данном случае есть только один).

Проблема в том, что объект groupby может содержать любую комбинацию RGB ценности. Например, у меня может быть столбец R и G, но не B, или у меня может быть только столбец R, или у меня не будет ни одного столбца RGB.

Из-за этого факта int функция apply, I пришлось ввести операторы if для каждого столбца, чтобы иметь счетчики для каждого цвета, независимо от того, находится ли его значение в объекте groupby или нет.

Есть ли у меня какой-либо другой вариант для принудительного применения logi c из цвета функция, используя что-то другое вместо применения таким (уродливым) способом?

Например, в этом случае я заранее знаю, что мне нужны подсчеты ровно для трех категорий - R, G и B. Мне нужно что-то вроде сгруппируйте по столбцу и этим трем значениям.

Могу ли я сгруппировать фреймы данных по этим трем категориям (серии, dict, функции?) И всегда получать ноль или сумму для всех трех категорий, независимо от того, существуют они в группе или нет?

1 Ответ

0 голосов
/ 16 июня 2020

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

#changed data for more combinations

df = pd.DataFrame(
    [
        ['W', 'R', 1],
        ['X', 'G', 2],
        ['Y', 'R', 1],
        ['Y', 'B', 3],
        ['Z', 'R', 2],
        ['Z', 'B', 2],
        ['Z', 'G', 1],
     ],
     columns=['client', 'status', 'cnt']
)
print (df)
  client status  cnt
0      W      R    1
1      X      G    2
2      Y      R    1
3      Y      B    3
4      Z      R    2
5      Z      B    2
6      Z      G    1

Затем добавляется параметр fill_value=0 для замены несоответствующих значений (отсутствующих значений) в 0:

df_gb = df.groupby(['client', 'status']).cnt.sum().unstack(fill_value=0)
#alternative
df_gb = df.pivot_table(index='client', 
                       columns='status', 
                       values='cnt', 
                       aggfunc='sum', 
                       fill_value=0)
print (df_gb)
status  B  G  R
client         
W       0  0  1
X       0  2  0
Y       3  0  1
Z       2  1  2

Вместо этого создается вспомогательная функция DataFrame со всеми комбинациями 0,1 и добавлен новый столбец для output:

from  itertools import product

df1 = pd.DataFrame(product([0,1], repeat=3), columns=['R','G','B'])
#change colors like need
df1['output'] = ['no','blue','green','color2','red','red1','red2','all']
print (df1)
   R  G  B  output
0  0  0  0      no
1  0  0  1    blue
2  0  1  0   green
3  0  1  1  color2
4  1  0  0     red
5  1  0  1    red1
6  1  1  0    red2
7  1  1  1     all

Затем для замены значений выше 1 на 1 используется DataFrame.clip:

print (df_gb.clip(upper=1))
   B  G  R output
0  0  0  1    red
1  0  1  0  green
2  1  0  1   red1
3  1  1  1    all

И последний используется DataFrame.merge для нового выходного столбца, нет параметра on, поэтому он объединен пересечением столбцов в обоих DataFrames, здесь R,G,B:

df2 = df_gb.clip(upper=1).merge(df1)
print (df2)
   B  G  R output
0  0  0  1    red
1  0  1  0  green
2  1  0  1   red1
3  1  1  1    all
...