Подсчитайте вхождения значений в pandas и поместите результат в одну строку

#python #pandas

#python #pandas

Вопрос:

Мой фрейм данных выглядит следующим образом:

 id   column1   column2
a    x         l
a    x         n
a    y         n
b    y         l
b    y         m
  

В настоящее время я генерирую подсчеты значений с помощью этого

 def value_occurences(grouped, column_name):
    return (grouped[column_name].value_counts(normalize=False, dropna=False)
        .to_frame('count_' column_name)
        .reset_index(level=1))

result = value_occurences(grouped, 'column1') 

"""
>>>result
id   column1   count_column1
a    x         2
a    y         1
b    y         1
"""
  

И мне нужно подсчитать вхождения значений в этом формате:

 id   column1   column2
a   'x:2; y:1' 'l:1; n:2'
b   'y:1'      'l:1; m:1'
  

как я могу преобразовать свой результат в этот формат?

Ответ №1:

Я знаю, что здесь не используются Pandas, но это все равно может вам помочь:

 from collections import defaultdict
import pandas as pd

df = pd.DataFrame({'id': ['a', 'a', 'a', 'b', 'b'], 'column1': ['x', 'x', 'y', 'y', 'y'], 'column2': ['l', 'n', 'n', 'l', 'm']})
#   id column1 column2
# 0  a       x       l
# 1  a       x       n
# 2  a       y       n
# 3  b       y       l
# 4  b       y       m

c1_counter = defaultdict(lambda: defaultdict(int))
c2_counter = defaultdict(lambda: defaultdict(int))
for idx, row in df.iterrows():
    c1_counter[row['id']][row['column1']]  = 1
    c2_counter[row['id']][row['column2']]  = 1

new_data = defaultdict(list)
for k, v in c1_counter.items():
     new_data['id'].append(k)
     c1_items = [f'{v_}:{f}' for v_, f in v.items()]
     c2_items = [f'{v_}:{f}' for v_, f in c2_counter[k].items()]
     new_data['column1'].append(';'.join(c1_items))
     new_data['column2'].append(';'.join(c2_items))

df = pd.DataFrame(new_data)
  

тогда df будет выглядеть:

   id  column1  column2
0  a  x:2;y:1  l:1;n:2
1  b      y:2  l:1;m:1
  

Ответ №2:

Вы можете сначала сгенерировать группы df по df.groupby(['id']) и применить value_counts к каждой группе:

 import io, pandas as pd

def seqdict(x):
    return ', '.join('{}:{}'.format(*i) for i in sorted(x.items()))

def value_occurences(df):
    return pd.DataFrame({c: {i: seqdict(d.iloc[:,j].value_counts().to_dict())
                  for i, d in df.groupby(by=['id']) } 
              for j, c in enumerate(df.keys()) 
             })

grouped = pd.read_table(io.StringIO("""id   column1   column2
a    x         l
a    x         n
a    y         n
b    y         l
b    y         m
"""), sep='s ')

value_occurences(grouped)
  

Результаты:

     column1   column2
a  x:2, y:1  l:1, n:2
b       y:2  l:1, m:1
  

Ответ №3:

Вы можете использовать groupby дважды. Добавьте, сначала вы подсчитываете значения, а затем объединяете их вместе:

 dfs = []
for column in ['column1', 'column2']:
    df_ = df.groupby(['id'])[column].value_counts()
    df_ = df_.index.get_level_values(-1)   ':'   df_.astype(str)
    df_ = df_.groupby('id').agg(lambda x: '; '.join(x)).rename(column)
    dfs.append(df_)
pd.concat(dfs, axis=1)