使用 groupby 后如何从 Pandas 数据帧中提取 select 行?
How to select rows from Pandas dataframe after using groupby?
从下面的数据框中,如何在不借助copying/pasting或中间数据结构的情况下获得拥有两只以上宠物的主人列表?
df = pd.DataFrame([['Jack', 'fuzzy',12], ['Jack', 'furry',13], ['Joe', 'scratchy',3], ['Jack', 'chirpy',40], ['Jeff', 'slithery',9], ['Jack', 'swimmy',1], ['Joe', 'feathery',14], ['Joe', 'oinky',11], ['Jack', 'stampy',1]],
columns=['Owner', 'Pet', 'Age'])
print(df)
Owner Pet Age
0 Jack fuzzy 12
1 Jack furry 13
2 Joe scratchy 3
3 Jack chirpy 40
4 Jeff slithery 9
5 Jack swimmy 1
6 Joe feathery 14
7 Joe oinky 11
8 Jack stampy 1
获取符合条件的布尔系列很容易:
df.groupby('Owner').count()['Pet']>2
Owner
Jack True
Jeff False
Joe True
Name: Pet, dtype: bool
实际上可以通过复制粘贴 groupby
语句来完成匹配(Jack 和 Joe):
df.groupby('Owner').count()['Pet'][df.groupby('Owner').count()['Pet']>2]
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
但如果条件语句很长,这会很痛苦,因为每次更改都需要重复。到目前为止发现的唯一其他方法是将系列放回数据框中并使用 query()
,但这感觉不太可能:
pd.DataFrame(df.groupby('Owner').count()['Pet']).query('Pet > 2')
Pet
Owner
Jack 5
Joe 3
还有比这些更好的方法吗?
您可以使用具有过滤功能的 .loc
索引器。
>>> df.groupby('Owner').Pet.count().loc[lambda p: p > 2]
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
或者,您可以使用 compress
方法。
>>> df.groupby('Owner').Pet.count().compress(lambda p: p > 2)
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
选项 1
使用 pd.factorize
和 np.bincount
f, u = pd.factorize(df.Owner.values)
b = np.bincount(f)
m = b > 2
u[m]
array(['Jack', 'Joe'], dtype=object)
或制作系列
pd.Series(b[m], u[m])
Jack 5
Joe 3
dtype: int64
选项 2
使用相同的 groupby
两次
2.1
时髦 lambda
(lambda p: p[p > 2])(df.groupby('Owner').Pet.count())
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
2.2
pipe
我宁愿使用@Mitch 的回答也不愿使用这个。
df.groupby('Owner').Pet.count().pipe(lambda p: p[p > 2])
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
时机
下面的代码
# Multiples of minimum runtime: Smaller is better.
#
pir1 pir2 pir3 mch1 mch2
10 1.0 2.984347 2.907198 2.422435 2.736712
30 1.0 3.396997 3.464083 3.023355 3.353150
100 1.0 3.646931 3.053890 2.586377 2.859365
300 1.0 4.541890 4.037132 3.054388 3.323939
1000 1.0 2.529670 2.438109 2.214494 2.415056
3000 1.0 3.212312 3.739621 3.062538 2.969489
10000 1.0 2.923211 2.807983 2.970712 2.637492
30000 1.0 2.790350 2.830328 2.978083 2.719900
def pir1(d, c):
f, u = pd.factorize(d.Owner.values)
b = np.bincount(f)
m = b > c
return pd.Series(b[m], u[m])
pir2 = lambda d, c: (lambda p: p[p > c])(d.groupby('Owner').Pet.count())
pir3 = lambda d, c: d.groupby('Owner').Pet.count().pipe(lambda p: p[p > c])
mch1 = lambda d, c: d.groupby('Owner').Pet.count().loc[lambda p: p > c]
mch2 = lambda d, c: d.groupby('Owner').Pet.count().compress(lambda p: p > c)
res = pd.DataFrame(
index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
columns='pir1 pir2 pir3 mch1 mch2'.split(),
dtype=float
)
for i in res.index:
d = pd.concat([df] * i, ignore_index=True)
c = 2 * i
for j in res.columns:
stmt = '{}(d, c)'.format(j)
setp = 'from __main__ import d, c, {}'.format(j)
res.at[i, j] = timeit(stmt, setp, number=10)
res.div(res.min(1), 0)
res.plot(loglog=True)
从下面的数据框中,如何在不借助copying/pasting或中间数据结构的情况下获得拥有两只以上宠物的主人列表?
df = pd.DataFrame([['Jack', 'fuzzy',12], ['Jack', 'furry',13], ['Joe', 'scratchy',3], ['Jack', 'chirpy',40], ['Jeff', 'slithery',9], ['Jack', 'swimmy',1], ['Joe', 'feathery',14], ['Joe', 'oinky',11], ['Jack', 'stampy',1]],
columns=['Owner', 'Pet', 'Age'])
print(df)
Owner Pet Age
0 Jack fuzzy 12
1 Jack furry 13
2 Joe scratchy 3
3 Jack chirpy 40
4 Jeff slithery 9
5 Jack swimmy 1
6 Joe feathery 14
7 Joe oinky 11
8 Jack stampy 1
获取符合条件的布尔系列很容易:
df.groupby('Owner').count()['Pet']>2
Owner
Jack True
Jeff False
Joe True
Name: Pet, dtype: bool
实际上可以通过复制粘贴 groupby
语句来完成匹配(Jack 和 Joe):
df.groupby('Owner').count()['Pet'][df.groupby('Owner').count()['Pet']>2]
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
但如果条件语句很长,这会很痛苦,因为每次更改都需要重复。到目前为止发现的唯一其他方法是将系列放回数据框中并使用 query()
,但这感觉不太可能:
pd.DataFrame(df.groupby('Owner').count()['Pet']).query('Pet > 2')
Pet
Owner
Jack 5
Joe 3
还有比这些更好的方法吗?
您可以使用具有过滤功能的 .loc
索引器。
>>> df.groupby('Owner').Pet.count().loc[lambda p: p > 2]
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
或者,您可以使用 compress
方法。
>>> df.groupby('Owner').Pet.count().compress(lambda p: p > 2)
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
选项 1
使用 pd.factorize
和 np.bincount
f, u = pd.factorize(df.Owner.values)
b = np.bincount(f)
m = b > 2
u[m]
array(['Jack', 'Joe'], dtype=object)
或制作系列
pd.Series(b[m], u[m])
Jack 5
Joe 3
dtype: int64
选项 2
使用相同的 groupby
两次
2.1
时髦 lambda
(lambda p: p[p > 2])(df.groupby('Owner').Pet.count())
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
2.2
pipe
我宁愿使用@Mitch 的回答也不愿使用这个。
df.groupby('Owner').Pet.count().pipe(lambda p: p[p > 2])
Owner
Jack 5
Joe 3
Name: Pet, dtype: int64
时机
下面的代码
# Multiples of minimum runtime: Smaller is better.
#
pir1 pir2 pir3 mch1 mch2
10 1.0 2.984347 2.907198 2.422435 2.736712
30 1.0 3.396997 3.464083 3.023355 3.353150
100 1.0 3.646931 3.053890 2.586377 2.859365
300 1.0 4.541890 4.037132 3.054388 3.323939
1000 1.0 2.529670 2.438109 2.214494 2.415056
3000 1.0 3.212312 3.739621 3.062538 2.969489
10000 1.0 2.923211 2.807983 2.970712 2.637492
30000 1.0 2.790350 2.830328 2.978083 2.719900
def pir1(d, c):
f, u = pd.factorize(d.Owner.values)
b = np.bincount(f)
m = b > c
return pd.Series(b[m], u[m])
pir2 = lambda d, c: (lambda p: p[p > c])(d.groupby('Owner').Pet.count())
pir3 = lambda d, c: d.groupby('Owner').Pet.count().pipe(lambda p: p[p > c])
mch1 = lambda d, c: d.groupby('Owner').Pet.count().loc[lambda p: p > c]
mch2 = lambda d, c: d.groupby('Owner').Pet.count().compress(lambda p: p > c)
res = pd.DataFrame(
index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
columns='pir1 pir2 pir3 mch1 mch2'.split(),
dtype=float
)
for i in res.index:
d = pd.concat([df] * i, ignore_index=True)
c = 2 * i
for j in res.columns:
stmt = '{}(d, c)'.format(j)
setp = 'from __main__ import d, c, {}'.format(j)
res.at[i, j] = timeit(stmt, setp, number=10)
res.div(res.min(1), 0)
res.plot(loglog=True)