飞道的博客

各项工具大pk,分组聚合哪家强?

285人阅读  评论(0)


小小明:「凹凸数据」专栏作者,Pandas数据处理专家,致力于帮助无数数据从业者解决数据处理难题。

凹凸们,大家好

先看一个小需求,其实是很常见的分组聚合问题。

今天我将带大家分别使用MySQLExcelPandasVBAPython来实现这个需求。

这么齐全的应该算是全网首发吧!当然也是为了让大家对分组聚合代码层面的实现能够更加熟悉。

MySQL实现分组统计

SQL语句:


   
  1. SELECT 
  2.   deal_date,
  3.   SUM(IF(AREA=  'A区'10))  'A区',
  4.   SUM(IF(AREA=  'B区'10))  'B区',
  5.   SUM(IF(AREA=  'C区'10))  'C区' 
  6. FROM
  7.   order_info 
  8. GROUP BY deal_date ;

结果:

Excel实现分组统计

首先创建数据透视表:

然后将对应的字段拖动到正确的位置:

然后打开透视表选项取消这两项勾选即可:

Pandas进行分组统计

读取数据:


   
  1. import pandas as pd
  2. df = pd.read_csv( "data.csv", encoding= "gb18030")
  3. df

结果:


order_id price deal_date area
0 S001 10 2019/1/1 A区
1 S002 20 2019/1/1 B区
2 S003 30 2019/1/1 C区
3 S004 40 2019/1/2 A区
4 S005 10 2019/1/2 B区
5 S006 20 2019/1/2 C区
6 S007 30 2019/1/3 A区
7 S008 40 2019/1/3 C区

使用数据透视表操作:


   
  1. df.pivot_table(values= "order_id", index= "deal_date",
  2.                columns= "area", aggfunc= "count", fill_value= 0)

上述代码相当于groupby操作:

df.groupby(["deal_date""area"])["order_id"].count().unstack(1, fill_value=0)

但我一般会这样写:

df.groupby(["deal_date""area"]).size().unstack(1, fill_value=0)

结果均为:

VBA实现分组统计

经过近1小时的痛苦的尝试,终于编写出了下面这段VBA代码,它模拟实现了分组计数的过程:


   
  1. Option Explicit
  2. Function is_exists(name As String)
  3. Dim sht As Worksheet
  4. For Each sht In Worksheets
  5. If sht.name = name Then
  6. is_exists = True
  7. Exit Function
  8. End If
  9. Next
  10. is_exists = False
  11. End Function
  12. Sub 分组统计()
  13. Dim LastRow, LastCol As Long
  14. Dim Sh As Worksheet
  15. 'Sh指代当前活动页
  16. Set Sh = Sheets("data")
  17. '当前活动页的最后一行
  18. LastRow = Sh.Cells(Rows.Count, 1).End(xlUp).row
  19. '当前活动页的最后一列
  20. LastCol = Sh.Cells(1, Columns.Count).End(xlToLeft).Column
  21. '定义D为字典
  22. Dim D As Object
  23. Set D = CreateObject( "Scripting.Dictionary")
  24. Dim row, i As Integer
  25. Dim key, value As String
  26. For i = 2 To LastRow
  27. key = Sh.Cells(i, 3).value
  28. value = Sh.Cells(i, 4).value
  29. '如果在字典里
  30. If Not D.exists(key) Then
  31. D.Add key, Array(0, 0, 0)
  32. End If
  33. row = D(key)
  34. If value = "A区" Then
  35. row(0) = row(0) + 1
  36. ElseIf value = "B区" Then
  37. row(1) = row(1) + 1
  38. ElseIf value = "C区" Then
  39. row(2) = row(2) + 1
  40. End If
  41. D(key) = row
  42. Next
  43. '调试输出字典存储的内容
  44. For Each key In D.keys()
  45. Debug.Print key & "," & Join(D(key), ",")
  46. Next
  47. Dim sht As Worksheet
  48. If is_exists( "result") Then
  49. Sheets( "result").Delete
  50. End If
  51. '在最后的位置增加一个sheet作为结果表
  52. Sheets.Add After:=Sheets(Sheets.Count)
  53. Set sht = Sheets(Sheets.Count)
  54. sht.name = "result"
  55. '屏幕刷新= false
  56. Application.ScreenUpdating = False
  57. '下面写出数据到结果表中,首先写出标题行
  58. sht.Range("A1").Resize(1, 4) = Application.Transpose(Array("deal_date", "A区", "B区", "C区"))
  59. sht.Range("A2").Resize(D.Count, 1) = Application.Transpose(D.keys)
  60. i = 2
  61. For Each row In D.items()
  62. sht.Cells(i, 2).Resize(1, 3) = row
  63. i = i + 1
  64. Next
  65. Application.ScreenUpdating = True
  66. End Sub

运行前:

点击按钮运行后:

立即窗口和工作表都看到了正确的结果输出,立即窗口看到重复2次的输出是因为我连续运行了两次。

Python实现分组计数

实现代码:


   
  1. import csv
  2. from collections  import namedtuple
  3. result = {}
  4. columns = [ "A区""B区""C区"]
  5. areas_map = dict(zip(columns,  range( len(columns))))
  6. with open( "data.csv", encoding= "gb18030") as f:
  7.     f_csv = csv.reader(f)
  8.     headers = next(f_csv)
  9.     resultSet = namedtuple( "resultSet", headers)
  10.      for r in f_csv:
  11.         row = resultSet(*r)
  12.         areas = result.setdefault(row.deal_date, [ 000])
  13.         areas[areas_map[row.area]] +=  1
  14. result

结果:

{'2019/1/1': [111], '2019/1/2': [111], '2019/1/3': [101]}

借助Pandas转换为表结构方便查看:

pd.DataFrame.from_dict(result, 'index', columns=["A区""B区""C区"])

结果:


A区 B区 C区
2019/1/1 1 1 1
2019/1/2 1 1 1
2019/1/3 1 0 1

下面用Python模拟一下Pandas数据透视表实现分组统计的过程:


   
  1. import csv
  2. from collections  import namedtuple, Counter
  3. result = Counter()
  4. with open( "data.csv", encoding= "gb18030") as f:
  5.     f_csv = csv.reader(f)
  6.     headers = next(f_csv)
  7.     resultSet = namedtuple( "resultSet", headers)
  8.      for r in f_csv:
  9.         row = resultSet(*r)
  10.         result[(row.deal_date, row.area)] +=  1
  11. result

结果:


   
  1. Counter({( '2019/1/1''A区'):  1,
  2.          ( '2019/1/1''B区'):  1,
  3.          ( '2019/1/1''C区'):  1,
  4.          ( '2019/1/2''A区'):  1,
  5.          ( '2019/1/2''B区'):  1,
  6.          ( '2019/1/2''C区'):  1,
  7.          ( '2019/1/3''A区'):  1,
  8.          ( '2019/1/3''C区'):  1})

第二步Pandas还需再对这个结果进行重塑才得到最终所需要的结果,具体重塑的过程实际实现较为复杂,但可以借助category的Series模拟实现一下:


   
  1. indexs = result.keys()
  2. index = pd.Series( map(lambda x: x[ 0], indexs), dtype= 'category')
  3. columns = pd.Series( map(lambda x: x[ 1], indexs), dtype= 'category')
  4. values = result.values()
  5. data = np.zeros(( len(index.cat.categories),  len(columns.cat.categories)))
  6. for x, y, v in zip(index.cat.codes, columns.cat.codes, values):
  7.     data[x, y] = v
  8. result = pd.DataFrame(data, index=index.cat.categories,
  9.                       columns=columns.cat.categories, dtype= 'int8')
  10. result

结果:


A区 B区 C区
2019/1/1 1 1 1
2019/1/2 1 1 1
2019/1/3 1 0 1

总结

其实不管用什么语言和工具,分组聚合统计的核心原理都是:

今天我给大家同时演示了MySQL、Excel、Pandas、VBA和Python实现分组聚合,通过对比,或许大家能自己总结出各项工具的优劣和适用场景。

欢迎你在下方评论区留言,发表你的看法,给大家分享和互动。

????《数据结构和算法基础Python语言实现》60个好玩的实例代码+300幅图表+模块化编程,从找出并简化核心问题到估算数据规模和算法复杂度,再到编写代码,帮你掌握数据结构和算法这一核心技能!点击可看详情/购买!????

感谢北京大学出版社支持!

后台回复关键词「进群」,即刻加入读者交流群~

在看”和“点赞”是对文章最好的支持 


转载:https://blog.csdn.net/zhuxiao5/article/details/112646006
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场