2017-01-14 12 views
2

У меня есть следующие панды dataframe имени matches:Панды: преобразование строк в один столбец на основе состояния

id | name | age 
1 | a  | 19 
1 | b  | 25 
2 | c  | 19 
2 | d  | 22 

Я использую groupby + count(), если значение определенного столбца (age) удовлетворяет условию (x < 21). Результат записывается в новый столбец (new_col):

matches['new_col'] = matches.groupby(['id'])['age'].transform(lambda x: x[x < 21].count()) 

dataframe тогда выглядит следующим образом:

id | name | age | new_col 
1 | a  | 19 | 1 
1 | b  | 25 | 1 
2 | c  | 19 | 2 
2 | d  | 18 | 2 

Теперь я хотел бы выводить результат в более понятным способом, то есть, name -колонка каждой строки, где выполняется условие (возраст < 21), должно быть записано в новый столбец, например result.

Я бы ожидать что-то вроде этого (однако, могут быть и другие способы для достижения этой цели, возможно, даже сделать Тхи уже на первом этапе, где я добавить new_col.):

id | name | age | new_col | result 
1 | a  | 19 | 1  | a 
1 | b  | 25 | 1  | a 
2 | c  | 19 | 2  | c,d 
2 | d  | 18 | 2  | c,d 

Последний шаг (добавление колонка result), где я застрял прямо сейчас.

ответ

0

теперь я сделал это так: groupBy + apply + ап применить функцию, которая добавляет новый столбец:

matches = matches.groupby(['id']).apply(concat) 

CONCAT является:

def concat(group): 
    group['result'] = "{%s}" % ', '.join(group['name'][group['age'] < 21]) 
    return group 

любые другие/более эффективные решения?

2

Первый фильтр строк по boolean indexing и затем aggregate, последняя join на оригинал:

matches1 = matches[matches.age < 21] 
          .groupby(['id'])['name'].agg({'result':', '.join, 'new_col': len}) 
print (matches1) 
    new_col result 
id     
1   1  a 
2   2 c, d 

print (matches.join(matches1, on='id')) 
    id name age new_col result 
0 1 a 19  1  a 
1 1 b 25  1  a 
2 2 c 19  2 c, d 
3 2 d 18  2 c, d 

Другим решением с doubletransform, но в первую очередь необходимо sort_values для следующего с использованием ffill значений, которые являются >=21:

matches = matches.sort_values(['id','age']) 
g = matches[matches.age < 21].groupby(['id'])['name'] 
matches['new_col'] = g.transform(len) 
matches['result'] = g.transform(', '.join) 
matches[['new_col','result']] = matches[['new_col','result']].ffill() 

print (matches) 
    id name age new_col result 
0 1 a 19  1  a 
1 1 b 25  1  a 
3 2 d 18  2 d, c 
2 2 c 19  2 d, c 

Лучшее объяснение необходимо sorting немного изменено df:

print (matches) 
    id name age 
0 1 a 25 > first value is filter out by condition 
1 1 b 12 
2 2 c 19 
3 2 d 18 

matches = matches.sort_values(['id','age']) 
g = matches[matches.age < 21].groupby(['id'])['name'] 
matches['new_col'] = g.transform(len) 
matches['result'] = g.transform(', '.join) 
matches[['new_col','result']] = matches[['new_col','result']].ffill() 

print (matches) 
    id name age new_col result 
1 1 b 12  1  b 
0 1 a 25  1  b 
3 2 d 18  2 d, c 
2 2 c 19  2 d, c 

print (matches.sort_index()) 
    id name age new_col result 
0 1 a 25  1  b 
1 1 b 12  1  b 
2 2 c 19  2 d, c 
3 2 d 18  2 d, c