功能式Python中的探索性数据分析
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~
这里有一些技巧来处理日志文件提取。假设我们正在查看一些Enterprise Splunk提取。我们可以用Splunk来探索数据。或者我们可以得到一个简单的提取并在Python中摆弄这些数据。
在Python中运行不同的实验似乎比试图在Splunk中进行这种探索性的操作更有效。主要是因为我们可以无所限制地对数据做任何事。我们可以在一个地方创建非常复杂的统计模型。
理论上,我们可以在Splunk中做很多的探索。它有各种报告和分析功能。
但是...
使用Splunk需要假设我们知道我们正在寻找什么。在很多情况下,我们不知道我们在寻找什么:我们正在探索。可能会有一些迹象表明,一些RESTful API处理速度很慢,但还不止于此。我们如何继续?
第一步是获取CSV格式的原始数据。怎么办?
读取原始数据
我们将首先用一些附加函数来包装一个CSV.DictReader对象。
面向对象的纯粹主义者会反对这个策略。 “为什么不扩展DictReader?”他们问。我没有一个很好的答案。我倾向于函数式编程和组件的正交性。对于一个纯粹的面向对象的方法,我们不得不使用更复杂的混合来实现这一点。
我们处理日志的一般框架是这样的。
with open("somefile.csv") as source:
rdr = csv.DictReader(source)
这使我们可以读取CSV格式的Splunk提取物。我们可以迭代阅读器中的行。这是诀窍#1。这不是非常棘手,但我喜欢它。
with open("somefile.csv") as source:
rdr = csv.DictReader(source)
for row in rdr:
print( "{host} {ResponseTime} {source}{Service}".format_map(row) )
我们可以 - 在一定程度上 - 以有用的格式报告原始数据。如果我们想粉饰一下输出,我们可以改变格式字符串。那就可能是“{主机:30s} {回复时间:8s} {来源:s}”或类似的东西。
过滤
常见的情况是我们提取了太多,但其实只需要看一个子集。我们可以更改Splunk过滤器,但是,在完成我们的探索之前,过量使用过滤器令人讨厌。在Python中过滤要容易得多。一旦我们了解到需要什么,就可以在Splunk中完成。
with open("somefile.csv") as source:
rdr = csv.DictReader(source)
rdr_perf_log = (row for row in rdr if row['source'] == 'perf_log')
for row in rdr_perf_log:
print( "{host} {ResponseTime} {Service}".format_map(row) )
我们已经加入了一个生成器表达式来过滤源行,能够处理一个有意义的子集。
投影
在某些情况下,我们会添加额外的源数据列,这些列我们并不想使用。所以将通过对每一行进行投影来消除这些数据。
原则上,Splunk从不产生空列。但是,RESTful API日志可能会导致数据集中包含大量列标题,这些列标题是基于请求URI一部分的代理键。这些列将包含来自使用该代理键的一个请求的一行数据。对于其他行,在这一列中没有任何用处。所以要删除这些空列。
我们也可以用一个生成器表达式来做到这一点,但是它会变得有点长。生成器函数更容易阅读。
def project(reader):
for row in reader:
yield {k:v for k,v in row.items() if v}
我们已经从原始阅读器中的一部分项目构建了一个新的行字典。我们可以使用它来包装我们的过滤器的输出。
with open("somefile.csv") as source:
rdr = csv.DictReader(source)
rdr_perf_log = (row for row in rdr if row['source'] == 'perf_log')
for row in project(rdr_perf_log):
print( "{host} {ResponseTime} {Service}".format_map(row) )
这将减少在for语句内部可见的未使用的列。
符号更改
row['source']符号会变得比较笨重。使用types.SimpleNamespace比用字典更好。这使得我们可以使用row.source。
这是一个很酷的技巧来创造更有用的东西。
rdr_ns= (types.SimpleNamespace(**row) forrowinreader)
我们可以将其折叠成这样的步骤序列。
with open("somefile.csv") as source:
rdr = csv.DictReader(source)
rdr_perf_log = (row for row in rdr if row['source'] == 'perf_log')
rdr_proj = project(rdr_perf_log)
rdr_ns = (types.SimpleNamespace(**row) for row in rdr_proj)
for row in rdr_ns:
print( "{host} {ResponseTime} {Service}".format_map(vars(row)) )
请注意我们对format_map()方法的小改动。从SimpleNamespace的属性中,我们添加了vars()函数来提取字典 。
我们可以用其他函数把它写成一个函数来保留句法对称性。
def ns_reader(reader):
return (types.SimpleNamespace(**row) for row in reader)
的确,我们可以把它写成一个像函数一样使用的lambda结构
ns_reader = lambda reader: (types.SimpleNamespace(**row) for row in reader)
虽然ns_reader()函数和ns_reader()lambda的使用方式相同,但为lambda编写文档字符串和doctest单元测试稍微困难一些。出于这个原因,应该避免使用lambda结构。
我们可以使用map(lambda row:types.SimpleNamespace(** row),reader)。有些人喜欢这个发生器表达式。
我们可以用一个适当的for语句和一个内部的yield语句,但是从一个小的东西里写大的语句似乎没有什么好处。
我们有很多选择,因为Python提供了如此多的函数式编程功能。虽然我们不会经常把Python视作一种功能性语言。但我们有多种方法来处理简单的映射。
映射:转换和派生数据
我们经常会有一个非常明显的数据转换列表。此外,我们将有一个衍生的数据项目越来越多的列表。衍生项目将是动态的,并基于我们正在测试的不同假设。每当我们有一个实验或问题,我们可能会改变派生的数据。
这些步骤中的每一个:过滤,投影,转换和派生都是map-reduce管道的“map”部分的阶段。我们可以创建一些较小的函数,并将其应用于map()。因为我们正在更新一个有状态的对象,所以我们不能使用一般的map()函数。如果我们想实现一个更纯粹的函数式编程风格,我们将使用一个不可变的namedtuple而不是一个可变的SimpleNamespace。
def convert(reader):
for row in reader:
row._time = datetime.datetime.strptime(row.Time, "%Y-%m-%dT%H:%M:%S.%F%Z")
row.response_time = float(row.ResponseTime)
yield row
在我们探索的过程中,我们将调整这个转换函数的主体。也许我们将从一些最小的转换和派生开始。我们将用一些“这些是正确的?”的问题来继续探索。当我们发现不工作时,我们会从中取出一些。
我们的整体处理过程如下所示:
with open("somefile.csv") as source:
rdr = csv.DictReader(source)
rdr_perf_log = (row for row in rdr if row['source'] == 'perf_log')
rdr_proj = project(rdr_perf_log)
rdr_ns = (types.SimpleNamespace(**row) for row in rdr_proj)
rdr_converted = convert(rdr_ns)
for row in rdr_converted:
row.start_time = row._time - datetime.timedelta(seconds=row.response_time)
row.service = some_mapping(row.Service)
print( "{host:30s} {start_time:%H:%M:%S} {response_time:6.3f} {service}".format_map(vars(row)) )
请注意语句主体的变化。convert()函数产生我们确定的值。我们已经在for循环中添加了一些额外的变量,我们不能100%确定。在更新convert()函数之前,我们会看看它们是否有用(甚至是正确的)。
减量
在减量方面,我们可以采取稍微不同的加工方式。我们需要重构我们之前的例子,并把它变成一个生成器函数。
def converted_log(some_file):
with open(some_file) as source:
rdr = csv.DictReader(source)
rdr_perf_log = (row for row in rdr if row['source'] == 'perf_log')
rdr_proj = project(rdr_perf_log)
rdr_ns = (types.SimpleNamespace(**row) for row in rdr_proj)
rdr_converted = convert(rdr_ns)
for row in rdr_converted:
row.start_time = row._time - datetime.timedelta(seconds=row.response_time)
row.service = some_mapping(row.Service)
yield row
接着用一个yield代替了print()。
这是重构的另一部分。
for row in converted_log("somefile.csv"):
print( "{host:30s} {start_time:%H:%M:%S} {response_time:6.3f} {service}".format_map(vars(row)) )
理想情况下,我们所有的编程都是这样的。我们使用生成器函数来生成数据。数据的最终显示保持完全分离。这使我们可以更自由地重构和改变处理。
现在我们可以做一些事情,例如将行收集到Counter()对象中,或者可能计算一些统计信息。我们可以使用defaultdict(list)按服务对行进行分组。
by_service= defaultdict(list)
for row in converted_log("somefile.csv"):
by_service[row.service] = row.response_time
for svc in sorted(by_service):
m = statistics.mean( by_service[svc] )
print( "{svc:15s} {m:.2f}".format_map(vars()) )
我们决定在这里创建具体的列表对象。我们可以使用itertools按服务分组响应时间。它看起来像是正确的函数式编程,但是这种实施在Pythonic函数式编程形式中指出了一些限制。要么我们必须对数据进行排序(创建列表对象),要么在分组数据时创建列表。为了做好几个不同的统计,通过创建具体的列表来分组数据通常更容易。
我们现在正在做两件事情,而不是简单地打印行对象。
创建一些局部变量,如svc和m。我们可以很容易地添加变化或其他措施。
使用没有参数的vars()函数,它会从局部变量中创建一个字典。
这个使用vars()而没有参数的行为就像locals()一样是一个方便的技巧。它允许我们简单地创建我们想要的任何局部变量,并将它们包含在格式化输出中。我们可以侵入我们认为可能相关的各种统计方法中。
既然我们的基本处理循环是针对converted_log(“somefile.csv”)中的行,我们可以通过一个小小的,易于修改的脚本探索很多处理选择。我们可以探索一些假设来确定为什么某些RESTful API处理速度慢,而其他处理速度则很快。
问答
相关阅读
此文已由作者授权腾讯云+社区发布,原文链接:https://cloud.tencent.com/developer/article/1007247?fromSource=waitui
功能式Python中的探索性数据分析的更多相关文章
- python进行EDA探索性数据分析
1.查看数据的类型概况 cols = [c for c in train.columns] #返回数据的列名到列表里 print('Number of features: {}'.format(l ...
- python中字符串的操作方法
python中字符串的操作方法大全 更新时间:2018年06月03日 10:08:51 作者:骏马金龙 我要评论这篇文章主要给大家介绍了关于python中字符串操作方法的相关资料,文中通过示例代码详细 ...
- python中的引用
作为一个python初学者,今天被一个python列表和词典引用的问题折磨了很久,但其实了解了缘由也很简单,记录在此备忘. 首先背书python中的引用对象问题: 1. python不允许程序员选择采 ...
- 从python中copy与deepcopy的区别看python引用
讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用.python的内存管理. python中的一切事物皆为对象,并且规定参数的传递都是对象的引用.可能这样说听起来比较难懂,对比 ...
- python中print()函数的“,”与java中System.out.print()函数中的“+”
python中的print()函数和java中的System.out.print()函数都有着打印字符串的功能. python中: print("hello,world!") 输出 ...
- 【归纳】正则表达式及Python中的正则库
正则表达式 正则表达式30分钟入门教程 runoob正则式教程 正则表达式练习题集(附答案) 元字符\b代表单词的分界处,在英文中指空格,标点符号或换行 例子:\bhi\b可以用来匹配hi这个单词,且 ...
- Python在金融,数据分析,和人工智能中的应用
Python在金融,数据分析,和人工智能中的应用 Python最近取得这样的成功,而且未来似乎还会继续下去,这有许多原因.其中包括它的语法.Python开发人员可用的科学生态系统和数据分析库.易于 ...
- Python中利用函数装饰器实现备忘功能
Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下 " ...
- Python中模块之time&datetime的功能介绍
time&datetime的功能介绍 1. time模块 1. 时间的分类 1. 时间戳:以秒为单位的整数 2. 时间字符格式化:常见的年月日时分秒 3. 时间元祖格式:9大元素,每个元素对应 ...
随机推荐
- MT6575 3G切换2G
因为了节省成本,需要从现在的3G方案切换置2G方案,做的修改,做个笔记. 一: 将MTK给过来的补丁编译出如下文件. 二:在mediatek/custom/common/modem/ 路径下增加一个 ...
- 【翻译】在Ext JS集成第三方库
原文地址:http://www.sencha.com/blog/integrating-ext-js-with-3rd-party-libraries/ 作者:Kevin Kazmierczak Ke ...
- android Google推荐的容器SparseArrayCompat简介
android Google推荐的容器SparseArrayCompat简介 private static SparseArrayCompat<BaseFragment> mCaches ...
- JavaScript单线程的疑问与解答
问: JavaScript是单线程的,有任务队列,比如使用setTimeou(func,secs)来在secs毫秒后向任务队列添加func.但是,setTimeout后面跟一个死循环,那么死循环导致任 ...
- 漫谈jdbc
本文可作为北京尚学堂jdbc课程的学习笔记; 简介 jdbc是什么东西? jdbc全称(Java Database Connectivity java数据库连接) 它是干什么的? 至于它是干什么的,那 ...
- c++ list 合并操作函数实例
#include <list> #include <iostream> using namespace std; //list 链表的打印 void print(list< ...
- LeetCode(45)-Bulls and Cows
题目: You are playing the following Bulls and Cows game with your friend: You write down a number and ...
- Which SQL statement is the trump card to the senior software developer
Which SQL statement is the trump card to the senior software developer MA Genfeng ...
- JVM学习--(二)内存模型、可见性、指令重排序
我们将根据JVM的内存模型探索java当中变量的可见性以及不同的java指令在并发时可能发生的指令重排序的情况. 内存模型 首先我们思考一下一个java线程要向另外一个线程进行通信,应该怎么做,我们再 ...
- app ionic1 微信 微博 分享功能的实现
微信分享 1.登录微信开放平台注册账户 2.创建一个移动应用 (app) 审核过后会有一个appid 之后安装插件的时候会用到 3.在这个应用上面填写 包名 和 签名 就可以了 包名和签名的 ...