为此,我忍受了好几个小时。
考虑这些数据
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
和{{ 1}},而n
正确输入了两次地址,但第三次却弄乱了。结果,上述两个e
操作都会计数不足一些人拥有的苹果数量。理想的输出是:
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')
。我正在考虑尝试分配新名称,这些新名称可以正确识别重复的名称或地址,但无法弄清楚该怎么做。任何帮助表示赞赏。
答案 0 :(得分:2)
另一种方法:
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
列中的每个组编号
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
然后使用名称和总和df.groupby('name',as_index=False).sum()
的groupby返回
name apples group
0 a 36 4
1 b 28 8
2 c 18 0
3 d 17 0
4 e 38 6
现在,相同的地址行将具有相同的组号,因此您再次在group
列上进行分组,并使用apples = 'sum'
和name = first or last
的{{3}}函数来保持第一个/最后一个名称实例。
d = {'name':'first','apples':'sum'}
df1 = df.groupby('name',as_index=False).sum().groupby('group').agg(d)
然后仅对值进行排序并重置索引以获取输出。
答案 1 :(得分:1)
如果我理解正确,则可以创建从地址到名称的映射。然后使用此映射覆盖名称,然后像平常一样执行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
的 first 地址是正确的地址。