группировать то или иное - PullRequest
0 голосов
/ 18 октября 2018

Терпи меня за это, я ломал голову над этим часами.

Рассмотрим эти данные

np.random.seed(2)
apples = np.random.randint(10,20,9)
df = pd.DataFrame({'name':list('aabbcdeee'), 'addr':list('mmznjjkkx'), 'apples':apples})[['name','addr','apples']]

Если name то же самое, то это тот же человек, если addr это то же самое, это также и тот же человек.Я хочу посчитать количество яблок, которое есть у каждого человека.Обычно это было бы тривиально:

In [50]: df[['apples', 'name']].groupby('name').sum()
    Out[50]:
      apples
name
a         36
b         28
c         18
d         17
e         38

или df[['apples', 'addr']].groupby('addr').sum(), поскольку они должны возвращать один и тот же результат. НО , адрес j ввел свое имя как c и d, в то время как имя b ввел свой адрес как z и n, тогда как e правильно ввел адрес дважды, ноиспортил 3-й раз.В результате обе вышеуказанные операции groupby не учитывают количество яблок, которыми владеют некоторые люди.Идеальный вывод:

In [52]: %paste
pd.DataFrame({'name':list('aabbcceee'), 'addr':list('mmnnjjkkk'), 'apples':apples}).groupby('name').apples.sum()

## -- End pasted text --
Out[52]:
name
a    36
b    28
c    35
e    38
Name: apples, dtype: int32

Я могу идентифицировать индексы с ошибочными адресами или именами, используя наборы:

sameNames = df.name[df.name.duplicated()].index
sameAddr = df.addr[df.addr.duplicated()].index
sameNameORaddr = df.name[(df.name.duplicated() | df.addr.duplicated())].index

, так что ошибки здесь:

In [47]: sameNameORaddr.difference(sameNames).union(sameNameORaddr.difference(sameAddr))
Out[47]: Int64Index([2, 3, 4, 5, 8], dtype='int64')

, но я не могу понять, как использовать это для выполнения groupby.Я думал о попытке присвоить новые имена, которые могут правильно идентифицировать дубликаты имен или адресов, но не могу понять, как это сделать.Любая помощь приветствуется.

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Другой подход:

df['group'] = df.groupby('addr').ngroup()

d = {'name':'first','apples':'sum'}
df1 = df.groupby('name',as_index=False).sum().groupby('group').agg(d)

df1 = df1.sort_values('name').reset_index(drop=True)

print (df1)

# Output:

  name  apples
0   a    36
1   b    28
2   c    35
3   e    38

Объяснение:

Первое использование groupby.ngroup для нумерации каждой группы в addr col

df['group'] = df.groupby('addr').ngroup()

  name addr apples group
0   a   m    18     2
1   a   m    18     2
2   b   z    16     5
3   b   n    12     3
4   c   j    18     0
5   d   j    17     0
6   e   k    12     1 
7   e   k    11     1 
8   e   x    15     4

Затем groupby с именем и суммой df.groupby('name',as_index=False).sum() возвращает

   name  apples group
 0  a     36     4
 1  b     28     8
 2  c     18     0
 3  d     17     0
 4  e     38     6

Теперь те же строки адресов будут иметь тот же номер группы, поэтому вы снова группируете по столбцу group и используете groupby.agg функция с apples = 'sum' и name = first or last для сохранения первого / последнего экземпляра имени.

d = {'name':'first','apples':'sum'}
df1 = df.groupby('name',as_index=False).sum().groupby('group').agg(d)

Затем просто сортируйте значения и сбрасывайте индекс, чтобы получить вывод.

0 голосов
/ 18 октября 2018

Если я правильно понимаю, вы можете создать сопоставление от адреса к имени.Затем перезапишите имена с этим сопоставлением и выполните GroupBy как обычно:

s = df.drop_duplicates('addr').set_index('addr')['name']
df['name'] = df['addr'].map(s)

res = df.groupby('name', as_index=False)['apples'].sum()

print(res)

  name  apples
0    a      36
1    b      28
2    c      35
3    e      38

Начальный drop_duplicates с addr работает в предположении, что первый адрес, введенный для любогоname является правильным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...