我有一个数据框:
import pandas as pd
import numpy as np
df = pd.DataFrame()
df['name'] = ['john','sam','john','john','dean','dean','maggi',
'ram','maggi','ana','sam','sam']
df['pt'] = [23, 32, 45, 65, 65, 45, 32, 45, 90, 10, 32, 22]
如果名称在名称列中仅出现一次,我想用其他名称替换。
所以我的输出将是:
name pt
0 john 23
1 sam 32
2 john 45
3 john 65
4 dean 65
5 dean 45
6 maggi 32
7 other 45
8 maggi 90
9 other 10
10 sam 32
11 sam 22
在我的原始数据中,值有数百个,因此使用
df.replace
或map
是不可行的。
np.where
仅适用于二进制列。所以我被困在这里。
谢谢
答案 0 :(得分:4)
将numpy.where
与duplicated
一起使用以选择所有唯一的行,或者将transform
与size
一起使用以指定阈值来进行更通用的解决方案:
df['name'] = np.where(~df['name'].duplicated(keep=False), 'other', df['name'])
或者:
df['name'] = np.where(df.groupby('name')['name'].transform('size') == 1, 'other', df['name'])
print (df)
name pt
0 john 23
1 sam 32
2 john 45
3 john 65
4 dean 65
5 dean 45
6 maggi 32
7 other 45
8 maggi 90
9 other 10
10 sam 32
11 sam 22
另一种解决方案,谢谢@乔恩·克莱门茨(Jon Clements):
df.name.where(df.groupby('name')['name'].transform('size') > 1, 'other', inplace=True)
答案 1 :(得分:3)
这是使用pd.Series.value_counts
和pd.DataFrame.loc
的矢量化解决方案:
s = df['name'].value_counts(sort=False)
df.loc[df['name'].isin(s[s == 1].index), 'name'] = 'other'
print(df)
name pt
0 john 23
1 sam 32
2 john 45
3 john 65
4 dean 65
5 dean 45
6 maggi 32
7 other 45
8 maggi 90
9 other 10
10 sam 32
11 sam 22
性能基准化
如果您有很多重复的名字,可以使用Categorical Data来提高性能。以下是Python 3.6,Pandas 0.19上的计时。
def jpp(df):
s = df['name'].value_counts(sort=False)
df.loc[df['name'].isin(s[s == 1].index), 'name'] = 'other'
return df
def jez(df):
df['name'] = np.where(df.groupby('name')['name'].transform('size') == 1, 'other', df['name'])
return df
def jon(df):
df['name'] = df['name'].apply(lambda name, counts=Counter(df['name']): name if counts[name] > 1 else 'other')
return df
assert jpp(df).equals(jez(df))
assert jpp(df).equals(jon(df))
%timeit jpp(df) # 49.4 ms per loop
%timeit jez(df) # 56.2 ms per loop
%timeit jon(df) # 274 ms per loop
设置
df = pd.DataFrame({'name': ['john','sam','john','john','dean','dean','maggi',
'ram','maggi','ana','sam','sam'],
'pt': [23, 32, 45, 65, 65, 45, 32, 45, 90, 10, 32, 22]})
df['name'] = df['name'].astype('category')
df['name'] = df['name'].cat.add_categories('other')
df = pd.concat([df, pd.concat([df.iloc[:5]]*100000)])