VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > 简明python教程 >
  • Pandas进阶笔记 (一) Groupby 重难点总结(3)

"State").transform(inspect)
<class 'pandas.core.series.Series'>
2    1
3    3
Name: a, dtype: int64
<class 'pandas.core.series.Series'>
2     3
3    11
Name: b, dtype: int64
<class 'pandas.core.frame.DataFrame'>
   a   b
2  1   3
3  3  11
<class 'pandas.core.series.Series'>
0    4
1    5
Name: a, dtype: int64
<class 'pandas.core.series.Series'>
0     6
1    10
Name: b, dtype: int64

从打印结果我们也清晰地看到两点:transform每次只计算一列;会出现计算了一个组整体的情况,这有点令人费解,待研究。

从上面的对比,我们直接得到了一个有用的警示:不要传一个同时涉及到多列的函数给transform方法,因为那么做只会得到错误。例如下面的代码所示:

def subtract(x):
    return x["a"] - x["b"]

try:
    df_6.groupby("State").transform(subtract)
except Exception:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    formatted_lines = traceback.format_exc().splitlines()
    print(formatted_lines[-1])

KeyError: ('a', 'occurred at index a')

另一个警示则是:在使用 transform 方法的时候,不要去试图修改返回结果的长度,那样不仅会引发错误,而且traceback的信息非常隐晦,很可能你需要花很长时间才能真正意识到错误所在。

def return_more(x):
    return  np.arange(3)

try:
    df_6.groupby("State").transform(return_more)
except Exception:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    formatted_lines = traceback.format_exc().splitlines()
    print(formatted_lines[-1])

ValueError: Length mismatch: Expected axis has 6 elements, new values have 4 elements

这个报错信息有点别扭,期待返回6个元素,但是返回的结果只有4个元素;其实,应该说预期的返回为4个元素,但是现在却返回6个元素,这样比较容易理解错误所在。

最后,让我们以一条有用的经验结束这个talk:如果你确信自己想要的操作时同时作用于多列,并且速度最好还很快,请不要用transform方法,Talk9有一个这方面的好例子。


Talk 7:agg 用法总结

(1)一次对所有列调用多个函数

df_0.groupby("A").agg([np.sum, np.mean, np.min])

  C D
  sum mean amin sum mean amin
A            
bar 0.978077 0.244519 -1.343518 -2.042817 -0.510704 -2.064735
foo 0.184686 0.046172 -1.854274 3.113988 0.778497 0.210586

(2)一次对特定列调用多个函数

df_0.groupby("A")["C"].agg([np.sum, np.mean, np.min])

  sum mean amin
A      
bar 0.978077 0.244519 -1.343518
foo 0.184686 0.046172 -1.854274

(3)对不同列调用不同函数

df_0.groupby("A").agg({"C": [np.sum, np.mean], "D": [np.max, np.min]})

  C D
  sum mean amax amin
A        
bar 0.978077 0.244519 0.917027 -2.064735
foo 0.184686 0.046172 1.348597 0.210586
df_0.groupby("A").agg({"C": "sum", "D": "min"})

  C D
A    
bar 0.978077 -2.064735
foo 0.184686 0.210586

(4)对同一列调用不同函数,并且直接重命名

df_0.groupby("A")["C"].agg([("Largest", "max"), ("Smallest", "min")])

  Largest Smallest
A    
bar 1.477379 -1.343518
foo 1.145852 -1.854274

(5)对多个列调用同一个函数

agg_keys = {}.fromkeys(["C", "D"], "sum")
df_0.groupby("A").agg(agg_keys)

  C D
A    
bar 0.978077 -2.042817
foo 0.184686 3.113988

(6)注意agg会忽略缺失值,这在计数时需要加以注意

df_7 = pd.DataFrame({"ID":["A","A","A","B","B"], "Num": [1,np.nan, 1,1,1]})
df_7

  ID Num
0 A 1.0
1 A NaN
2 A 1.0
3 B 1.0
4 B 1.0
df_7.groupby("ID").agg({"Num":"count"})

  Num
ID  
A 2
B 2

注意:Pandas 中的 count,sum,mean,median,std,var,min,max等函数都用C语言优化过。所以,还是那句话,如果你在大数据集上使用agg,最好使用这些函数而非从numpy那里借用np.sum等方法,一个缓慢的程序是由每一步的缓慢积累而成的。


Talk 8:**Filtration ** 易错点剖析

通常,在对一个 dataframe 分组并且完成既定的操作之后,可以直接返回结果,也可以视需求对结果作一层过滤。这个过滤一般都是指 filter 操作,但是务必要理解清楚自己到底需要对组作过滤还是对组内的每一行作过滤。这个Talk就来讨论过滤这个话题。

【例子】找出每门课程考试分数低于这门课程平均分的学生

df_8 = pd.DataFrame({"Subject": list(chain(*[["Math"]*3,["Computer"]*3])),
                    "Student": list(chain(*[["Chan", "Ida", "Ada"]*2])),
                    "Score": [80,90,85,90,85,95]})

df_8

  Subject Student Score
0 Math Chan 80
1 Math Ida 90
2 Math Ada 85
3 Computer Chan 90
4 Computer Ida 85
5 Computer Ada 95

这样一个需求是否适合用 filter 来处理呢?我们试试看:

try:
    df_8.groupby("Subject").filter(lambda x: x["Score"] < x["Score"].mean())
except Exception:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    formatted_lines = traceback.format_exc().splitlines()
    print(formatted_lines[-1])

TypeError: filter function returned a Series, but expected a scalar bool

显然不行,因为 filter 实际上做的事情是要么留下这个组,要么过滤掉这个组。我们在这里弄混淆的东西,和我们初学 SQL时弄混 WHERE 和 HAVING 是一回事。就像需要记住 HAVING 是一个组内语法一样,请记住 filter 是一个组内方法。

我们先解决这个例子,正确的做法如下:

df_8.groupby("Subject").apply(lambda g: g[g.Score < g.Score.mean()])

    Subject Student Score
Subject        
Computer 4 Computer Ida 85
Math 0 Math Chan 80

而关于 filter,我们援引官方文档上的例子作为对比

df_9 = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
                          'foo', 'bar'],
                    'B' : [1, 2, 3, 4, 5, 6],
                    'C' : [2.0, 5., 8., 1., 2., 9.]})
df_9

  A B C
0 foo 1 2.0
1 bar 2 5.0
2 foo 3 8.0
3 bar 4 1.0
4 foo 5 2.0
5 bar 6 9.0
df_9.groupby('A').filter(lambda x: x['B'].mean() > 3.)

  A B C
1 bar 2 5.0
3 bar 4 1.0
5 bar 6 9.0

Part 3:groupby 应用举例

Talk 9:组内缺失值填充

df_10 = pd.DataFrame({"ID":["A","A","A","B","B","B"], "Num": [100,np.nan,300,np.nan,500,600]})
df_10

  ID Num
0 A 100.0
1 A NaN
2 A 300.0
3 B NaN
4 B 500.0
5 B 600.0

相关教程