如何在Pandas中高效地选择多个数值范围?

4

我在重写一些旧代码的时候,偶然发现了这个片段。

df = pd.DataFrame({
'x': ['a', 'b', 'c', 'd', 'e', 'dc', 'ca', 'cd', 'cf', 'cv', 'cs', 'ca', 'ac', 'fc'],
'a': [34, 28, 51,5,120,12,45,56,67,54,34,32,1213,2]})

five = df[df['a'] < 5]
ten = df[(df['a'] > 5)  &  (df['a'] < 10)]
twenty = df[(df['a'] > 10)  &  (df['a'] < 20 )]
thirty = df[(df['a'] > 20)  &  (df['a'] < 30 )]
forty = df[(df['a'] > 30)  &  (df['a'] < 40 )]
fifty = df[(df['a'] > 40)  &  (df['a'] < 50 )]
sixty =  df[(df['a'] > 50)  &  (df['a'] < 60)]
over =  df[(df['a'] > 60)]

基本上有一个数据框,我需要将在一定范围内的数值分组。有多个范围。稍后在箱线图中使用分组的值。

上面的代码可以完成任务,但我很确定有更好的方法来做到这一点!

问题:如果我需要创建1000个组怎么办?我想更动地改变边缘值并添加新的组,如何实现?

3个回答

1
你可以使用pd.cut()创建分组区间,然后使用df.groupby()创建一个分组对象,其中包含由bin拆分的数据框列表。然后你可以将其存储在列表中。
(注意:我没有为每个数据框命名,因为如你所说,如果有1000个数据框,为每个命名是没有意义的。你可以将它们存储在列表中。)
import pandas as pd

cuts = [5,10,20,30,40,50,60]   #pd.cut take 2 elements from this for grouping (5,10); (30,40) etc
cols = ['x','a']             #columns to keep in final list of dataframes

df1['bin'] = pd.cut(df1['a'], cuts, right=False)   #create bins
group = df1.groupby('bin')   #groupby bins (grouper object)
dfs = [j[cols] for i,j in group]   #Iterate over grouper object to get dfs


#Printing block (ignore this)
k = list(zip(cuts,cuts[1:]))
for i,j in enumerate(dfs):
    print('Group in range',k[i],':')
    print(j)
    print('\n')

Group in range (5, 10) :
   x  a
3  d  5


Group in range (10, 20) :
    x   a
5  dc  12


Group in range (20, 30) :
   x   a
1  b  28


Group in range (30, 40) :
     x   a
0    a  34
10  cs  34
11  ca  32


Group in range (40, 50) :
    x   a
6  ca  45


Group in range (50, 60) :
    x   a
2   c  51
7  cd  56
9  cv  54    

您可以查看 cutgroupby 的文档以获取更多详细信息


1
谢谢您的回复!我测试了您的解决方案,它非常好用,但在大型数据集上,Anky的解决方案表现得更快(不太确定为什么)。虽然答案中的基本思路是相同的,但我必须选择他的答案。只是想解释一下我的选择,因为我讨厌没有解释的情况。谢谢! - Geom

1

方法#1

您可以使用 pd.cut 来创建动态分组,并将其保存在字典中,然后针对各个数据帧引用每个键:

bins = [0,5,10,20,30,40,50,60,np.inf]
labels = ['five','ten','twenty','thirty','forty','fifty','sixty','over']

u = df1.assign(grp=pd.cut(df1['a'],bins,labels=labels))
d = dict(iter(u.groupby("grp")))

测试运行:

print(f"""Group five is \n\n {d['five']}\n\n 
         Group forty is \n\n{d['forty']} \n\n Group over is \n\n{d['over']}""")

Group five is 

      x  a   grp
3    d  5  five
13  fc  2  five

 
Group forty is 

     x   a    grp
0    a  34  forty
10  cs  34  forty
11  ca  32  forty 

 Group forty is 

     x     a   grp
4    e   120  over
8   cf    67  over
12  ac  1213  over

方法#2 你也可以使用locals将字典键保存为本地变量,但是使用字典方法更好:

bins = [0,5,10,20,30,40,50,60,np.inf]
labels = ['five','ten','twenty','thirty','forty','fifty','sixty','over']

u = df1.assign(grp=pd.cut(df1['a'],bins,labels=labels))
d = dict(iter(u.groupby("grp")))
for k,v in d.items():
    locals().update({k:v})

print(over,'\n\n',five,'\n\n',sixty)

     x     a   grp
4    e   120  over
8   cf    67  over
12  ac  1213  over 

      x  a   grp
3    d  5  five
13  fc  2  five 

     x   a    grp
2   c  51  sixty
7  cd  56  sixty
9  cv  54  sixty

1
你可以使用 pandas.cut() 来将某些值分配到特定的区间中。例如,你可以在数据帧中添加一个额外的列 category,如下所示: df['category'] = pd.cut(df['a'], bins=np.arange(5, 65, 5)) 这将给你以下数据帧:
     x     a      category
0    a    34  (30.0, 35.0]
1    b    28  (25.0, 30.0]
2    c    51  (50.0, 55.0]
3    d     5           NaN
4    e   120           NaN
5   dc    12  (10.0, 15.0]
6   ca    45  (40.0, 45.0]
7   cd    56  (55.0, 60.0]
8   cf    67           NaN
9   cv    54  (50.0, 55.0]
10  cs    34  (30.0, 35.0]
11  ca    32  (30.0, 35.0]
12  ac  1213           NaN
13  fc     2           NaN

然后可以使用新列中的值在groupby()方法中进行分组。您提供的分箱参数可以相当灵活地创建(如上所示)。 cut()函数的文档在这里:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.cut.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接