谁的数据?
数据专业关键职位—解释
一个古老而美好的东西…
一个数据分析师和一个数据科学家有什么区别?一个 BI 分析师和一个业务分析师?一个数据架构师和一个数据工程师?
不,没有笑点。
数据职业和职位在过去几年中发生了巨大的变化,新的职位出现了,旧的定义不再适用,很难定义您合适的头衔,在招聘时更难找到满足您需求的角色。
几年前,当我试图为我的团队招聘一名初级数据分析师时,我创建了下面的数据职位字典。虽然没有满,但随着新职位的不断出现,它有望帮助你们中的一些人在组建团队或根据市场衡量自己和规划自己的技能时安排自己的思路。
准备好了吗?
数据分析师 学者,数据艺术家
使用各种工具,如预测模型、统计算法和数据挖掘来解决数据相关问题。
通常采用个案定制的方法,利用分析结果指导大范围的运营。喜欢原始数据,知道什么时候深入研究,什么时候建模,拥有(或将为您提供)所有答案。具有技术头脑和积极实践方法的角色。
最喜欢的任务:应用数据模型获得洞察力
数据科学家 革新者,新时代大师
问题解决者。研究问题的已知和未知的潜在解决方案,考虑业务需求来源的生态系统和手头的可用数据来权衡它们,以选择首选解决方案并将其从研究转化为产品。
最喜欢的任务:尝试应用新的研究作为商业问题的解决方案
数据工程师 足智多谋的数据管道工
铺平道路,构建可扩展、可维护且稳定的管道,整个组织的数据流通过这些管道进行分析。
平衡专业工程与实验数据应用需求。
最喜欢的任务:将新数据流集成到组织数据管道中
数据架构师 数据流的导体
创建和维护跨组织的数据存储和消费标准。将数据计划与技术框架和业务目标结合起来,确定战略举措和优化机会。组织数据攀登架的设计者。
最喜欢的任务:设计新数据流的消费
BI 分析师 密码学家,将数据转化为见解
基于现有数据产生可操作的见解,以引导和支持组织内的决策制定。两者都通过分析数据了解过去和评估现在来维持和改变业务。具有强烈商业视角的报道专家。
最喜欢的任务:为商业利益相关者提供可行的见解
业务分析师(营销、产品、系统、财务…)
数据作者和说书人
精通数据的商业专家。与 BI 分析师相比,不太担心收集数据,更关注业务角度。这位分析师是她所在领域的专家,完全致力于用数据支持定义的业务目标(尽管分析不一定是定量的),同时始终牢记组织的效率和盈利能力。
最喜欢的任务:通过收集相关数据研究业务问题,做出清晰简单的决策
数据治理分析师 组织数据的把关人
监控跨系统和来源的组织数据。分析数据差异、可用性和一致性等问题,以提高对数据的信心。以质量为导向,控制数据流。
最喜欢的任务:分析不规则的生产测量以发现根本原因
数据产品经理 面向业务的数据梦想家
确定在公司产品中使用数据的需求和潜在优势。定义可交付的数据,这些数据可以是现有产品的一部分,也可以是供消费者(内部或外部)使用的独立数据产品。数据驱动产品的战略家和远见者,塑造了数据专业人员的运营框架。
最喜欢的任务:为业务问题定义一个数据解决方案
一般来说,所有数据专业人员的技能可以映射到 3 个主要领域,每个领域的熟练程度不同;
- 研究
包括理论数据科学应用、统计学方面的大量知识,并要求与最近的学术界和行业发展保持同步 - 技术
控制各种工具,实现数据操作、分析、构建数据管道和处理大数据量 - 业务
深入了解和熟悉公司所处的市场,包括竞争对手、客户、产品以及公司的战略
将如上所述的不同职位映射到这些技能领域,如下所示:
一系列有明确重点的技能
不是所有公司的所有数据组都会包括以上所有职位,当然也不是作为单个团队成员。在小公司中,由几个利益相关者负责整个端到端的范围是很常见的。然而,这是我给你的建议——你为这个职位选择角色的方式将极大地影响你的预期产出,所以要明智地选择。
例如,数据科学家和数据工程师的职责有时可以统一在同一个人之下。然而,你应该明智地考虑你真正需要的是什么;有工程能力的数据科学家还是有数据科学取向的工程师?
类似地,当定义你是哪种类型的分析师时,考虑这些:你更关注数据还是业务用例?你是现场专家还是精通事实的记者?
我确信我的定义并不完全符合你认识的每一个专业人士,甚至可能不符合你对自己的定义。
然而,我希望它仍然有助于您了解我们工作的数据职业生态系统,并提出一些要点供您下次招聘/学习新技能/重新定位职业等时考虑。
数据争论
一个无代码介绍摔跤你的比特和字节。
图片由皮克斯拜的 Gerd Altmann 提供
数据采集
首先你得拿到你的数据!这可能涉及到从更大的数据集中提取所需的数据。它可能涉及合并两个或多个数据集。
数据形状
一只狗不仅仅是为了圣诞节,而是为了生活,对吗?好吧,数据争论不仅仅是你在数据科学项目中做一次就再也不会重温的事情。这是一项持续的活动。分析的某些方面适合“长”格式的数据,而其他方面更适合“宽”格式的数据。在适当的时候你会更深刻地理解这些术语,但是现在,我们可以举一个例子。假设你对一组人进行了纵向研究,你测量了他们在节食期间的体重。有些人属于体制 A,有些人属于体制 b。您的数据可能是这样组织的:
受试者 ID |日期|制度|体重
您感兴趣的一项分析可能是绘制每个受试者的体重随时间的变化。在这种情况下,上面的“长”格式是合适的,您可以立即绘制重量作为日期的函数。但是如果你想计算每个受试者的体重变化呢?您想要将上述内容重新格式化为
受试者 ID |制度|第一天的体重|最后一天的体重
随着分析的进行,您可能希望在这些格式之间进行切换。这里的要点是,没有一种数据格式可能在项目的所有阶段都是正确的。但是我们强调数据争论是第一步,因为在您进行任何其他事情之前,有一些关键的数据争论步骤要执行。
数据质量
初始数据争论的另一个重要方面是评估数据质量,并在可能的情况下进行改进。这里一个常见的错误是匆忙使用某种技术来估算(猜测)任何丢失的值。这真是不好的做法。想象一下“你曾经服用过违禁药物吗?”这个问题有答案还有一些空白的地方,人们拒绝回答。大多数人可能会如实回答“不”。用“否”来填充缺失的值是否看起来合理?受试者拒绝回答问题的事实可能是你想要保留的一条信息。
如果您正在构建一个机器学习模型来提前预测河流何时会发生洪水,并且河流水位传感器数据中存在缺失值,那么在盲目地用平均河流水位替换缺失值之前,值得探索这些数据。这种分析很可能揭示出,在缺失值之前,河流水位会快速上升,达到某个极端值,即监测站本身被淹没并停止运行的值!用(低得多的)平均水平替换那些丢失的值不是一个好主意!
是的,一些数据质量问题可以立即得到解决。让我们说,人们可以输入他们的性别自由格式’ F ‘,’ F ‘,‘女性’,‘女性’,’ Fem ‘,’ Woman’…你随后的探索将大大有助于首先清理这些一致的标准。
对数据质量的评估也有助于提炼你正在解决的实际问题。让我们回顾一下上面的饮食制度的例子。一个数据质量检查可能是计算每个受试者第一次和最后一次体重测量之间的天数。如果 80%的样本出现了一个月,20%出现了两个月,但你知道试验实际上持续了三个月,那会怎么样?你的数据质量似乎不足以回答这个问题“两种制度中的哪一种最终比另一种更好?”但是你可以修改这个问题来回答一个仍然有意义的问题“在第一个月,任何一种制度比另一种更有效吗?”
摘要
数据的采集显然倾向于在分析开始时预先加载。但这并不是说你不会决定一些额外的信息将是真正有用的,并在以后包括它。在整个项目过程中,数据的适当形状会发生变化,因此预计数据形状的争论将是一项持续的活动。事实上,分组和聚合是数据争论的一种形式,会影响数据的形状。数据质量是开始时需要评估的重要内容;你的项目失败了吗?有些问题可以而且应该在一开始就解决,但是许多问题应该标记出来,稍后再详细解决。记住,某些东西丢失的事实本身就是重要的信息!对您的数据质量持批评态度是您应该在整个工作过程中不断做的事情,而不只是在开始时做一次。
关于这篇文章
这是一个链接系列的第三篇文章,旨在简单介绍如何开始数据科学过程。你可以在这里找到简介,在这里找到上一篇文章,在这里找到系列文章。
Python 中的数据争论和监督学习
预测塞拉利昂的埃博拉疫情
这篇文章是由 尼古拉斯·迪亚兹 、MPP’20 在哈佛肯尼迪学院的一个项目基础上加上 杨子倪阿卜杜拉·赛义夫**
在这里 有一个 GitHub,里面有这个项目的 Jupyter 笔记本。
监督学习是世界上使用最广泛的机器学习形式之一。本文将指导您完成构建模型所需的一些最基本的步骤:导入数据、查看数据、以一致的格式输入数据、使用数据样本来训练和测试算法以及优化算法参数。
代码用 Python 显示,Python 是一种通用的编程语言。
我们选择的挑战是预测 2014-2016 年塞拉利昂爆发期间埃博拉在各地区的传播。
问题动机和目标
西非埃博拉病毒疫情(2014 年至 2016 年)造成 11 325 人死亡和重大社会经济破坏,其中大多数死亡发生在沿海国家塞拉利昂。在疫情期间,国家当局有足够的资源来隔离和治疗所有报告的病例,并阻止病毒的进一步传播。然而,事件总数的意外地方差异造成某些地区的应对能力不足(《世卫组织情况报告》,2014 年)。
在当前和未来的埃博拉紧急情况下,需要一个补充工具来指导跨地区的资源分配和提高应对效力。
数据清理
导入适当的库
首先,我们import
将在整个项目中使用的库。Pandas
是 Python 中主要的数据帧操作库,Sklearn
是运行机器学习模型的直观方式。对于Pandas
,我们将使用set_option
更改默认设置,以获得更舒适的大桌子显示。
*import pandas as pd
import numpy as np
import matplotlib.pyplot as pltpd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000from sklearn.metrics import mean_squared_error,median_absolute_error,r2_score,mean_absolute_error, accuracy_score, roc_curve, roc_auc_score, confusion_matrixfrom sklearn.model_selection import train_test_split, cross_val_score, GridSearchCVfrom sklearn.feature_selection import SelectKBest, chi2, f_classif
from sklearn.pipeline import Pipelinefrom sklearn.ensemble import RandomForestRegressor*
检查和理解数据
一旦我们导入了库,我们就用 Pandas 的read_csv()
方法加载数据。许多有用的方法允许快速检查数据帧:shape
、head()
、 tail()
和info
。
*df = pd.read_csv('sl_ebola.csv')
df.shape*
*df.head(14)*
*df.tail()*
*df.info*
看着上面的变量,我们有兴趣更深入地挖掘一些列。将value_counts()
应用到特定的列将返回每个类有多少个实例。
*print(df.Country.value_counts(), '\n')
print(df.District.value_counts(), '\n')
print(df['Ebola measure'].value_counts(), '\n')*
我们可以确认我们所有的行都来自塞拉利昂,并且所有地区都有相同数量的实例,这是我们所期望的。
删除因缺少值或不相关而无用的列
现在,前面的info
方法揭示了我们的一些列包含了大部分缺失的值。我们可以通过在我们的数据框架中使用drop()
方法来消除这些。inplace
设置为True
意味着它将修改我们的起始数据帧,我们不必重新定义它。我们可以使用head()
方法来查看一切是否正常。
*df.drop(columns=['Age group', 'Gender', 'Data as of', 'Outbreak identifier', 'Country', 'Indicator type'], inplace = True)df.head()*
删除不相关的无用行
我们还需要删除不会用于我们分析的行(例如,当它们是一个聚合时)。我们可以通过使用条件选择(!=
表示不同于)并将其保存到一个新的 dataframe 名称df2
来实现。我们在这一点上重新定义了数据帧,因为这样我们就不必在出错时从头开始。
*df2 = df[df.District != 'Aggregate']*
使用数据透视表操作重塑我们的数据框架
我们目前构建数据的方式还不能用于分析。现在,每个地区、每个星期、两个数据源中的每一个以及两个病例定义(确诊和可能)中的每一个都有单独的行。
为了运行我们的模型,我们希望确保每一行都代表每个地区每周的数字。我们可以通过结合pivot_tables
和一些快速的数据帧操作来实现。
*df3 = pd.pivot_table(df2, values=['Numeric'], index=['District', 'Epi week', 'Ebola data source'], columns=['Case definition'], aggfunc=np.sum)df3.head()*
*df4 = pd.DataFrame(df3.to_records())df4.rename({'(\'Numeric\', \'Confirmed\')' : 'Confirmed_cases', '(\'Numeric\', \'Probable\')' : 'Probable_cases', }, axis = 1, inplace = True)df4.head(10)*
*df5 = pd.pivot_table(df4, values=['Confirmed_cases', 'Probable_cases'], index=['District', 'Epi week'], columns=['Ebola data source'], aggfunc=np.sum)df6 = pd.DataFrame(df5.to_records())df6.rename({'(\'Confirmed_cases\', \'Patient database\')' : 'patient_database_confirmed', '(\'Confirmed_cases\', \'Situation report\')' : 'situation_report_confirmed', '(\'Probable_cases\', \'Patient database\')' : 'patient_database_probable', '(\'Probable_cases\', \'Situation report\')' : 'situation_report_probable', }, axis = 1, inplace = True)df6.head()*
瞧啊。这就是我们想要的。
让我们看看折叠所有信息后,我们有多少行。
*df6.shape*
导出到 CSV
此时,我们应该导出我们的结果,并在 dataframe 中使用to_csv()
方法给它们命名。通过这种方式,我们可以与他人共享我们重新调整的表格。
*df6.to_csv('sl_ebola_pivoted.csv')*
数据连接和特征工程
我们在这里没有显示代码,但下一步是将确认的埃博拉病例数据集与世界卫生组织和世界银行提供的许多不同的人口统计指标相结合。
我们还根据地理界限(哪个地区与哪个地区接壤)并通过在边界和报告病例之间建立“互动”创造了新的特征(或变量)。例如,最近几周在邻近的州有多少病例。
运行机器学习模型进行回归
探索回归的代码
我们现在准备开始构建我们的机器学习模型。此时,启动一个新的 Jupyter 笔记本并导入数据是一个好主意。
*df = pd.read_csv('ebola3.csv', index_col=0)
df.head(2)*
坚持
接下来,为了测试我们的模型的预测性,我们将“抽出”几个星期,这样我们的模型就不会在这些星期中进行训练。最后,我们将比较我们的模型对这三周的预测和实际发生的情况。这被称为“维持验证”,是一种确保我们不只是过度拟合的方法——也就是说,我们的模型基本上是在“记忆”数据集。
我们的三周是爆发的开始、顶点和结束。
*selected_weeks = ['2014-09-06', '2014-10-27','2014-12-29']
df_holdout = df[df.Datetime.isin(selected_weeks)]
df2 = df[~df.Datetime.isin(selected_weeks)]print(df.shape)
print(df_holdout.shape)
print(df2.shape)*
丢弃无关变量
我们将做更多的列删除,然后我们将分割我们的X
(预测值)和y
(目标变量)。出于本练习的目的,我们将重点关注来自“情况报告”来源的确诊病例。
*df2.drop(columns = ['X', 'District', 'patient_database_confirmed', 'Year', 'Week', 'Day', ‘Epi.week’, 'case_occured_PDC', 'case_occured_SRC'], inplace = True)X = df2.drop(columns = ['any_cases', 'Datetime', 'situation_report_confirmed'])
y = df2.situation_report_confirmed*
拆分数据的另一部分
除了在我们的维持集中分离三个星期,我们还做了一个train_test_split()
来分离 20%的数据集。这是为了获得一些关于我们模型性能的样本外统计数据。
*X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)*
随机森林回归量
我们现在利用我们导入的一种称为随机森林的算法,这是一种集成学习器,即多个决策树的聚合,可用于回归和分类。我们用我们想要的规格为我们的模型创建一个变量,然后我们用我们的火车组fit()
它。我们可以使用我们导入的指标之一(mean_squared_error
)来看看它的表现。
*random_forest = RandomForestRegressor(n_estimators = 100)
random_forest.fit(X_train, y_train)
mean_squared_error(y_test, random_forest.predict(X_test))*
对最佳参数进行网格搜索
现在,监督学习算法有许多参数可供选择。例如,在随机森林家族中,我们可以使用max_depth
来确定我们的树能长多高(也就是说,我们的决策节点能有多复杂)。先验地,对于树在我们的模型中应该有多高,没有正确或错误的答案。这取决于我们数据的性质。最好的选择是通过交叉验证。
在下面的代码中,我们使用sklearn
的GridSearchCV()
函数告诉 random forest 遍历许多不同的选项,并通过交叉验证返回得分最高的选项。然后,我们用这些最佳参数创建一个新的算法实例。最后,我们看到它的新得分。
为了好玩,这次让我们使用不同的度量(neg_mean_absolute_error
)来测试我们的算法做得如何。
*gsc = GridSearchCV(estimator=RandomForestRegressor(),param_grid={
'max_depth': range(3,7),
'n_estimators': (10, 50, 100, 1000),
}, cv=5, scoring='neg_mean_squared_error', verbose=0, n_jobs=-1) grid_result = gsc.fit(X, y)
best_params = grid_result.best_params_rfr = RandomForestRegressor(max_depth=best_params["max_depth"], n_estimators=best_params["n_estimators"], random_state=False, verbose=False)# Perform K-Fold CV
scores = cross_val_score(rfr, X, y, cv=10, scoring='neg_mean_absolute_error')np.mean(scores)*
分析我们坚持的结果
现在,我们可以返回到我们的维持集,并尝试基于我们的随机森林回归器和最佳参数来生成预测。按照与训练数据相同的方式将数据帧划分为X
和y
后,我们可以使用predict
方法为维持集中的每一行生成预测。
*X_holdout = df_holdout.drop(columns = ['any_cases', 'Datetime', 'situation_report_confirmed', 'X', 'District', 'Epi.week', 'patient_database_confirmed', 'Year', 'Week', 'Day', 'case_occured_PDC', 'case_occured_SRC'])y_holdout = df_holdout.situation_report_confirmeddf_holdout['prediction'] = random_forest.predict(X_holdout)*
我们现在可以在一个单独的数据框架中可视化这些结果,并将它们与实际数字进行比较。
*results = df_holdout[['District', 'Datetime', 'situation_report_confirmed', 'prediction']]results.head(20)*
最终模型描述
我们的最终模型考虑了塞拉利昂每个地区的一系列变量,每个地区过去病例数的信息,以及与周边地区的互动,以预测任何给定的一周是否会爆发埃博拉疫情,如果会,预计会有多少患者。
将我们的模型结果可视化的一种方法是在危机期间拿出三周的数据,然后测试我们的预测与实际发生的情况相比如何。我们选择危机开始时的一周,高峰时的一周,以及蔓延放缓时的一周。
从上面的可视化可以看出,我们的模型并没有产生完美的结果。在第三周的情况下,一些被给予低优先的北部地区最终出现了一些最高集中的病例。另一方面,图 1 中的中间一周准确地预测,病例最集中的地区将是塞拉利昂西北部。
总是想到潜在的偏见
当使用数据科学为政策和运营决策提供信息时,考虑到由于不完善的数据而引入偏差的可能性总是很重要的。
在我们的案例中,2013—2016 年疫情期间的埃博拉病例漏报已经得到广泛认可。根据工作人员的观察,世卫组织声称“报告的病例和死亡人数大大低估了疫情的严重程度”。根据一项估计,实际病例数超过报告病例数 2.5 倍。
由于我们的模型是根据报告的埃博拉病例数训练的,我们的预测平均来说会低估实际的埃博拉病例数。此外,漏报的程度可能与地区特征相关,而地区特征对于公平性的考虑也很重要。例如,较贫困地区的监测系统可能较差,导致未报告的病例数量较高。
因此,实际和预测的埃博拉病例数之间的差距在较贫困地区会更大,这可能导致资源分配不公平地对较贫困地区不利。如果没有进一步的信息来说明漏报是如何因地区而异的,我们就无法用有偏差的数据做出无偏差的预测。因此,如果我们的模型被采用,我们建议同时投资于监测系统,以产生更高质量的结果数据。
技术限制
我们目前方法的最大问题是,模型是根据疫情发生的整个时期做出预测的。换句话说,该模型可以查看数据和感染高峰,并知道预计数字何时增长和下降。在现实生活中,如果我们将这个模型应用于新的疾病爆发,那么我们将只有我们所在的那个星期的数据,但显然我们无法预测未来。如果疫情遵循类似的一般增长模式,这不会是一个问题,但不太可能是这样的情况。
结论
准备用于分析的数据是任何监督学习项目中最关键的一步。在这篇文章中,我们学习了一些有效帮助你成功的基本代码,以及模型训练、评估和优化工作流程的基本要素。
使用熊猫进行数据争论的备忘单
重要的熊猫
将原始数据转换成函数形式
在获取原始数据之后,数据争论是将原始数据转换为更具功能性的形式以用于数据分析、模型构建和数据可视化的最重要步骤。它涉及预处理、重组和清理操作,最终产品是一个易于访问的格式的数据集,可以随时进行分析和可视化。
本文的目的是展示在 pandas 中执行这些任务的一些关键操作**,pandas 是一个基于 python 的数据操作工具。这里的想法不是详尽地描述所有可用的 pandas 操作,而是给初级和中级用户一个基本功能的方便指南。**
这篇文章的内容被分成以下目录。
A.数据框架简介
- 创建数据帧
- 从数据帧中检索数据
- 汇总数据
B.数据争论
- 组合数据帧
- 重塑数据帧
- 处理空值
注意:除了最上面的图片,所有图片都是作者的,包括最后面的可下载备忘单和代码/代码结果。
数据框架简介
DataFrame 是 pandas 中最常用的结构化 API,用于在行(观察值)和列(变量)中存储数据,就像在表中一样。行标签被称为’索引,而列标签被称为’列。我们首先讨论定义数据帧的两种最常见的方法。虽然本文中的讨论仅限于二维数据集,但这里讨论的框架完全擅长处理高维数据。
创建数据框架
让我们从定义熊猫数据帧开始,如下所示。
作者图片
该数据帧由三列(包含三个标记为:col1、col2、col3 的变量)和三行(包含三个标记为:1、2 和 3 的观察值/索引)组成。定义数据帧最简单的方法是提供一个观察值列表然后在数据帧中按行排列。或者,我们可以提供数据作为一个字典,每个条目作为数据帧中的一列**。下面是这两种方法的代码。**
# Defining DataFrame by specifing a list of observations
df_1= DataFrame([['a', 'b', 'c'],
['d', 'e', 'f'],
['g', 'h', 'i']],
index = [1,2,3], columns = ['col1', 'col2', 'col3'])# Defining DataFrame by specifing a dictionary of columns
df_2= DataFrame({'col1': ['a', 'd', 'g'],
'col2': ['b', 'e', 'h'],
'col3': ['c', 'f', 'i']},
index = [1,2,3])
上面定义的df_1
和df_2
是相同的
从数据帧中检索数据
数据帧df_1
中存储的索引标签 (1,2,3) 、列标签 (col1,col2,col3) 和数据值 (a 到 i) 可以分别使用df_1.index,
df_1.columns,
和df_1.values
进行检索。
对于本文的大部分内容,我们将使用 Iris 数据集,而不是上面定义的 3X3 数据帧。这个公开可用的数据集以四种不同参数/变量 ( 萼片长度、萼片宽度、花瓣长度和花瓣宽度 ) 的形式包含关于三种不同品种的鸢尾花 (Setosa、Versicolour 和 Virginica) 的数据。我们可以使用 iris = pd.read_csv(‘[https://raw.githubusercontent.com/mwaskom/seaborndata/master/iris.csv'](https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv'))
导入并保存为熊猫数据帧
loc
是基于标签的函数,用于访问特定索引和/或列的数据,并返回为该特定索引/列存储的所有条目。iris.loc[[0,1]]
将返回索引为 0 和 1 的行:
相反,如果我们只想要标记为 0 & 1 的行中的某些特定列,我们可以使用 iris.loc[[0,1], [‘sepal_width’, ‘petal_length’]]
来指定列标签和行标签。
iloc
是切片数据帧的第二个选项。它基本上与loc
做同样的事情,但是利用基于整数的位置来访问数据,而不是索引和列标签。如果我们使用iris.iloc[1:4,0:3]
: 1:4
将返回索引为 1,2 的行& 3 在一个基于 0 的索引的数据帧iris
中,0:3
将返回索引为 0,1 & 2 的列。
虽然loc
和iloc
在大多数情况下足以对数据帧进行切片,但是切片方法的完整列表可以在这里找到。
汇总数据
本节列出了一些常用于检查数据帧的操作,以便更好地理解其内容。
iris.head(n)
和iris.tail(n)
分别返回数据帧的顶部和底部 n 行。iris.describe()
返回数据集中所有数值变量(列)的汇总。
iris[‘species’].value_counts()
将返回包含变量物种的每个唯一值的行数。
iris[‘sepal_length’].nunique()
将返回该列中唯一值的个数,正好是 35- 对列或行可以调用的数值运算有:
min()
(最小值)max()
(最大值)var()
(方差)std()
(标准差)sum()
(加法)等。
数据争论
组合数据帧
在本节中,我们将讨论两种非常重要的组合数据帧的方法
merge
使用一个 公共变量作为参考 来组合来自 不同数据帧 的观测值groupby
至 根据参考变量的输入,将数据分组到单个数据帧 中。
让我们从定义两个数据帧开始,这两个数据帧是使用数据切片的iloc
操作从前面讨论的 Iris 数据帧中提取的。首先,我们使用df_1 = iris.iloc[[1,51],3:]
对第 1 行和第 51 行的最后两列进行切片。
然后,我们使用iris.iloc[[1,51,101],[0,2,4]]
定义df_2
,这将为我们提供 iris 数据库中索引为 1、51 和 101 的行的第一、第三和第五列。
使用species
作为参考变量pd.merge(df_1, df_2, how = ‘outer’, on= ‘species’)
,操作merge
可以合并这两个数据帧。由于df_2
中提到的物种并不都在df_1
中出现,我们需要使用 how
参数指定哪些物种应该包含在合并的数据帧中。how = ‘outer’
表示两个数据集中任何一个的所有物种都必须包含在合并的数据集中。因为在df_1
中没有物种virginica
的条目,所以它的值是合并数据帧中变量petal_width
的NaN
。
然而,如果我们设置了how = ‘inner’
,那么只有那些同时出现在df_1
和df_2
中的物种才会被包含在合并的数据帧中。pd.merge(df_1, df_2, how = ‘inner’, on= ‘species’)
会给:
下面的文氏图展示了how
参数的使用。两个圆圈中的每一个都代表一个数据帧,阴影区域显示将使其成为合并的数据帧的观察结果。
作者图片
现在让我们从原始 iris 数据帧中检索另一个数据帧,这次由 8 行组成df_3 = iris.iloc[[1,2,3,4,51,52,53,54],[0,2,4]]
groupby
操作可用于使用df_3.groupby(‘species’)
拆分和合并df_3
中两个物种(setosa
& versicolor
)的数据。然后,我们可以使用get_group
分别访问两个species
的数据。
a.get_group('versicolor')
重塑数据帧
在本节中,我们将讨论重塑数据的关键操作。让我们从定义数据帧df_4 = iris.iloc[1:5,0:3]
开始
向df_4
添加新列需要指定变量名和相关数据
df_4[‘Species’] = [‘versicolor’, ‘versicolor’, ‘setosa’, ‘setosa’]
。请注意,列表的维度必须与现有数据帧中的行数相匹配。
现在,为了给这个数据帧添加一行,我们使用前面讨论过的loc
操作。 df_4.loc[5] = [4.9, 1.4, 1.3, ‘setosa’]
将返回:
为了删除行和列,我们使用了drop
操作。df_4.drop(‘Species’, axis=1)
将删除Species
列,而df_4.drop(2, axis = 0)
将删除索引为 2 的行。注意,我们在这里指定的是索引和列名,而不是相应的从 0 开始的索引值。axis
自变量用于区分行和列。0,默认值用于行,1 用于列。
我们还可以通过指定索引和列标签来同时删除行和列,如df_4.drop(index = 1, columns = [‘Species’]).
要制作包含两个或多个原始数据帧副本的数据帧,我们可以使用concatenate
功能。pd.concat([df_4,df_4])
将加入df_4
如下图所示
注意当两个df_4
副本被连接时,原始数据帧的索引标签是如何被保留的。传递一个额外的参数ignore_index=True
将导致索引标签的范围从 0 到 9。
在接下来的操作中,我们将使用我保存为 excel 文件并通过df = pd.read_excel(“weather.xlsx”)
导入的数据帧
注意这个数据帧的结构。这里有一个单变量temperature
。Day
和city
是两个不同的观察值,因为temperature
是在两个不同的city
(波士顿和纽约市)的五个Days
(周一至周五)记录的。我们可以使用pivot
操作df.pivot(index = ‘city’, columns= ‘Day’)
重新构建该数据帧,给出:
city
是这个重新构造的数据帧中的唯一索引,而Day
变量已经被转换成列。这种格式的数据框架更易于阅读,避免了重复的Day
变量,并且两个城市的temperature
值易于比较,因为它们彼此相邻。
为了介绍下一个整形操作,让我们导入另一个 excel 文件作为数据帧。df_1 = pd.read_excel(‘city_weather.xlsx’)
该数据帧与我们之前讨论的df
数据帧具有完全相同的数据,尽管格式非常不同。使用melt
操作,我们可以将这个数据帧转换成类似于我们之前从 excel 文件导入的数据帧。
pd.melt(df_1, id_vars = [“day”], var_name = [‘city’], value_name = ’temperature’)
melt
因此,与pivot
在数据帧重组方面的做法相反。
对于我们将讨论的最后一个数据重组操作,让我们定义一个自定义数据帧,如下所示:
df_2 = DataFrame(np.arange(16).reshape(4,4),
index = [['A', 'A', 'B', 'B'],['a','b','c','d']],
columns = [[1,1,2,2], [11,11,22,22]])
df_2.index.names = ['Index1', 'Index2']
df_2.columns.names = ['City', 'Town']
上面的代码是这样做的:它定义了一个由 0 到 15 的整数组成的数据帧,这些整数以4X4
的格式排列。指定了两个不同的索引([‘A’, ‘A’, ‘B’, ‘B’]
& [‘a’,’b’,’c’,’d’]
)和列([1,1,2,2]
& [11,11,22,22]
)标签以及每个标签的名称。生成的数据帧如下所示:
分层索引和列标签在复杂的数据集中并不少见,尤其是在描述许多不同变量之间的关系时。我们现在可以使用stack
操作来重构这个数据帧。df_2.stack(level = 0)
将在City
变量处重构数据帧,给出:-
类似地,df_2.stack(level = 1)
将如下转换Town
变量
处理空值
由于缺乏数据可用性,原始数据集通常包含一些空值(NaN
:非数字)。在进行数据建模和可视化之前,需要考虑和替换这些空值。让我们从定义包含 5 个空值的df_na_1
数据帧开始。
npn = np.nan
df_na_1 = DataFrame([[1, 2, 3, 4],
[4, 5, 6, npn],
[6, npn, 7, 8],
[9, npn, npn, npn]])
对该数据帧(df_na_1.isnull()
)调用isnull
操作将为所有空值返回 true
然后,我们可以使用dropna
操作df_na_1.dropna()
去掉所有具有单个空值的行/观察值,只剩下第一行。
如果我们想删除只有一个空值的列,设置axis = 1
(df_na_1.dropna(axis=1))
,现在我们只剩下第一列。
我们可以用选择的值代替空值,而不是丢弃它们。使用df_na_1.fillna({1:100, 2:200, 3:300})
,我们可以用不同列的不同值替换空值。标有1
的列中的所有空值都由100,
替换,标有2
的列由200
替换,依此类推。
让我们定义另一个数据帧df_na_2
df_na_2 = DataFrame([[100, 100, 100, 100],
[200, 200, 200, 200],
[300, 300, 300, 300],
[400, 400, 400, 400]])
使用df_na_1.combine_first(df_na_2)
,我们可以组合两个数据帧,使得df_na_1
的值为空时,它将被df_na_2
中的相应值替换。
下载备忘单
作者图片
上面显示的备忘单包含了本文中讨论的大部分关键概念,可以从这里下载。为了简洁起见,在 cheetsheet 中不可能给出详细的解释,所以请参考本文的正文。感谢阅读。
数据争论—从原始到干净的转变
简单的三个字的解释
当我第一次用谷歌搜索术语“争吵”时,我得到了一些奇怪的结果。牧马人的意思是围捕或看管牲畜如马而牧马人是看管牲畜、围捕牲畜并把它们组织成一个群体的人。完全相同的概念适用于数据争论。因此,在进行进一步分析之前,你应该争论你的数据,以获得更好的见解。
在这个故事中,我为你提供了一个简单的关于数据争论的三个词的解释。
让我们开始吧…
数据争论是收集数据、评估数据质量和清理数据的过程。
数据争论的 3 个步骤
从各种来源为项目收集的原始数据通常是不同的格式,不适合进一步的分析和建模。有时,这些收集的数据并不是真正干净和结构良好的。这使得处理这样的数据变得困难,从而导致犯错误,得到误导性的见解,并浪费你的宝贵时间。
人们常说,数据争论花费了整个项目时间的 70%到 80%,只留下 20%到 30%的时间用于探索和建模。
在数据争论过程结束时获得的数据然后用于进一步的分析、可视化或使用机器学习建立模型。
数据争论将原始数据转换成干净的、结构良好的数据
下面三张简单易懂的图片会让你对整个数据角力过程有所了解。
1。数据收集
根据您的数据科学项目,所需的数据可以从单个文件中获取,也可以分布在多个资源中以不同的格式获取。
有时,数据收集可能是一项具有挑战性的任务。
别担心!!!
Python 来寻求您的帮助。通过它的库,python 提供了许多有用的函数来从不同的资源中提取数据。根据数据资源及其格式,数据收集可能有不同的步骤。如果数据在一个文件中,那么收集就是下载该文件并将其读入您的项目。对于这个 Python,pandas 提供了广泛的read_
函数,如下图所示。
这就是 Python 中收集数据的方式
另一种方法是从数据库中收集数据,从网站上抓取数据,或者在 API 的帮助下收集数据。API 代表应用程序编程接口,它帮助你从 Twitter、脸书、Foursquare 等应用程序中获取数据。
API 是特定于应用程序的现成代码
也可以通过实验和数据记录器收集数据。如果您使用任何应用程序进行实验和数据记录,请搜索它的 API。在我的工作中,我通常使用加热室进行实验,并使用 PicoLog 数据记录器 API 来收集所需的数据。
对如何直接从网页中收集数据感到好奇??这是一篇关于网络抓取的有趣的 4 分钟阅读材料。
从网页中提取数据并存储到 excel 中—只需 4 个简单的步骤
towardsdatascience.com](/web-scraping-make-your-own-dataset-cc973a9f0ee5)
2.数据评估
收集之后,是时候评估你收集的数据了。但是等等…你要评估什么??答案是,
质量 和 整洁度
这不是数据探索,但是您将检查您的数据有多脏多乱。质量差的数据的内容有问题,这样的数据是脏数据。通常观察到的质量相关问题有:缺少值、数据不一致、数据类型不正确和重复。另一方面,杂乱的数据存在结构问题,即整洁性问题。正如 Hadley Wickham 在他的论文整理数据中所说,数据在以下情况下是整理好的,
- 每个变量形成一列。
- 每个观察值形成一行。
- 每种类型的观测单位形成一张表
数据评估中需要检查的内容
此外,数据可以通过视觉 和编程 和 进行评估。
视觉评估很简单,只要用你喜欢的任何应用程序打开数据,滚动它,并寻找质量,整洁的问题。在 Jupyter 笔记本中,可以使用head()
、tail()
和sample()
方法查看数据。
程序化评估使用小代码片段和 Python 函数来检查数据质量。熊猫提供了一系列检查数据质量的方法。
一些用于编程数据评估的 Python 方法
3.数据清理
现在是清理和组织数据的时候了。数据清理步骤始终专注于解决在数据评估阶段发现的质量和整洁问题。作为牧马人,直到现在,你也只是收集了数据,看了看它的问题。现在是时候行动起来,总结并组织好它,以获得更好的结果。
一些数据清理技术
根据问题和数据类型,使用不同的数据清理技术。
使用***seaborn . pair plot()***可以快速检查不同变量之间的相关性。有了这样的图,您将对哪些变量对您的分析不重要有一个部分的了解,并帮助您决定删除哪些列。
如果在同一个项目中有多个相似类型的数据集,那么最好将这些数据合并到一个数据集中。当执行这种数据合并时,最终数据集中可能存在重复或重复的数据点。这些重复的条目可以简单地删除。
这是一个关于合并数据集的有趣的 5 分钟阅读,
了解 Python pandas 中的 merge()和 concat()
towardsdatascience.com](/join-the-tables-ab7fd4fac26b)
另一个常见的问题是,数据类型不正确。在数据清理时,您应该确保数字存储为数值,日期和时间值应该存储为一个datetime
对象,等等。诸如pandas.to_numeric()
、pandas.to_datetime()
、pandas.to_timedelta()
、pandas.DataFrame.astype()
等 Python 函数随时可供您使用。
最终,通过删除或替换不正确的条目、删除不相关的变量以及添加新的变量,脏的和乱的数据会得到纠正。
总结一下,
数据的质量和结构是更好地洞察数据的两个重要方面。即使在数据被清理之后,重新评估数据以确保所需的质量和整洁也是一个好主意。这就是为什么在第一张图中,数据争论被视为一个迭代过程。请记住,高质量和组织良好的数据有助于进一步的分析、可视化和建模。
感谢您的时间和阅读!!
我希望你喜欢这个关于数据争论的三个词的解释。请随时添加您的反馈,并在 LinkedIn 上与我联系。
[## Suraj Gurav -副机械工程师-康耐视公司| LinkedIn
查看 Suraj Gurav 在全球最大的职业社区 LinkedIn 上的个人资料。Suraj 有 8 个工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/surajgurav17/)
与 Open Refine 的数据争论
马库斯·斯皮斯克拍摄的照片
大多数时候,当我们听到数据争论时,我们会想到使用 Python 或其他语言进行数据清理和操作。在大多数现实生活中,数据是如此的杂乱或庞大,以至于用一种语言来清理会感觉非常手工和痛苦。
Open Refine 是 Google 的一个免费开源工具,它可以清理杂乱的数据,将数据从一种格式转换为另一种格式,并使用其他 web 服务扩展数据。Open Refine 也可以在本地使用,所以你不用担心你的数据会泄露给公众。
在本文中,我们将介绍一个虚构的阳光药店的数据争论过程,该药店陈述了不同药物的销售情况。我们希望使用 Open Refine 来清理当前数据,使其具有标题:产品 ID、产品名称、包装类型、数量。转让和价格。
drive.google.com](https://drive.google.com/file/d/1wtdsf4R-2V1Gc2Jca4vm9Ln3Puvk720y/view?usp=sharing)
从上面的表格中,我们看到数据相当混乱。数据面临的一些挑战包括:
- 不正确的标题名称
- 不规则数据— (1,200)在假定的
Tranf. Quantity
列中。 - 表中嵌入了不需要的数据,例如,表中有我们不感兴趣的药店分支和每个分支的总销售额。
开放式精炼装置
Open Refine 可以在 Windows、Linux 和 Mac 上运行。要获得安装说明,请查看安装页面了解所有细节。
一旦安装并运行了它,您应该会在浏览器上看到这样一个页面:
打开优化起始页(图片由作者提供)
从这个起始页,您可以通过导入杂乱的数据来创建一个项目。请注意,数据可以是我们已经熟悉的形式— csv
、json
、xls
、xlsx
等。此外,您可以从多个来源获取数据,如您的计算机、URL、数据库等。让我们从计算机上的文件浏览器导入阳光药房数据,然后单击“下一步”。
项目创建前的格式设置(图片由作者提供)
在创建项目之前,Open Refine 向我们展示了项目的预览,以便我们在开始项目之前进行一些更改。如果我们注意,我们会注意到列标题是不正确的。我们将从这里开始清理我们的数据。当前的标题似乎没有用,所以如果我们删除它们,我们不会丢失任何重要的数据。同样,在第 2 行,我们可以得到更好的列标题,所以我们让 Open Refine 使用第 2 行的数据作为我们的列标题。我们可以通过以下方式做到这一点:
忽略项目中的前两行(图片由作者提供)
通过将ignore first
选项更新为 2,忽略前 2 行,并且Parse next
选项框使用第 2 行的数据作为新的列标题。
更新的列标题(作者图片)
这些列被更新了,尽管不正确,但它已经大大改善了我们数据的外观。我们将在进行过程中修改列标题。另外,请注意,数字周围的括号已被自动删除,数字已被转换为数字(绿色)。现在,我们可以通过单击 Create Project 按钮来创建项目。
新项目表(图片由作者提供)
我们现在有一个新项目。请注意,它在顶部显示了总行数。此外,每页最多只能显示 50 行,最少只能显示 5 行。这是所有奇迹发生的地方。让我们跳进来吧!
将日期提取到它自己的列中
我们首先将第一列中的日期提取到它自己的一列中——dates
列。在 Open Refine 中,我们可以通过在第一列的基础上创建一个新列来实现这一点。
基于另一列添加列(按作者排序的图像)
通过点击列标题上的插入符号,我们得到选项Edit column
,然后选择Add column based on this column
。这就是 Open Refine 变得非常有趣的地方,您可以编写代码来过滤这个非常混乱的列,以获得日期并将它们放在另一列中。
使用 GREL 过滤日期列(作者图片)
从上图中,我们给新列命名为Date
,然后继续使用通用精炼表达式语言来过滤该列。如你所见,它非常简单和干净。由于我们正在处理的工作表是针对三月份的,我们要求如果第一列中的任何一行包含单词“Mar ”,那么该列中的数据应该被复制到新的Date
列中。点击 OK,看看我们做了什么。
符合要求的行将被复制到新列中(图片由作者提供)
我们的过滤器工作了,带有日期的行被移动到Date
列。我们仍然需要对Date
列进行一些清理,因为我们仍然有许多空白和不需要的行。另外,请注意,我必须移动 4 页才能看到第 190 行上的第一个日期。
在日期栏中填写
接下来,我们要做的是对新的Date
列进行填充。向下填充用任何正好在它上面的数据填充空白行。此举将有助于填补我们的空白行。
在日期栏中向下填充(作者图片)
单击Date
列标题上的插入符号,选择编辑单元格选项,然后单击向下填充选项。最初,如果您在表单的第一页上,您可能看不到任何更改。这是因为在第 190 行之前,Date
列中没有数据,所以让我们在接下来的几页中检查一下。
填写日期栏(图片由作者提供)
我们可以有把握地假设第一列中的标题将用于Date
列中的第一个日期。此外,由于我们之前已经填充了该列,该列中剩余的空白单元格将用于第一个日期。因此,让我们用 2020 年 3 月 2 日星期一来填充空白处。我们将通过使用文本刻面来做到这一点。文本方面获取列中的每个唯一值,并显示它们的频率。点击日期标题上的插入符号,并选择 Facet - > Text Facet。
在日期列上做文本方面(图片由作者提供)
日期列上的文本方面(作者图片)
您可以在Date
列中看到各种不同的条目及其频率。但是,我们对空白单元格感兴趣,因此我们可以填写第一个日期。让我们向下滚动文本方面以查看空白单元格。
频率为 188 的空白单元格(图片由作者提供)
单击(空白)链接,只过滤那些在Date
列中有空白单元格的记录。您会看到所有记录都是在 2020 年 3 月 3 日星期二之前的。现在,让我们编辑空白并填入正确的日期。将鼠标悬停在(空白)链接上以查看并单击编辑链接。
编辑空白单元格的编辑链接(作者图片)
这将弹出一个提示,让您填写想要的值。我们将输入Monday, 02 Mar 2020
并点击应用。您可以看到,更新后我们有 0 个匹配行,因为在该列中不再有任何空白单元格。关闭日期方面以再次查看整个数据表。
编辑空白单元格(作者图片)
清理列和列标题
让我们重新命名我们的标题,让我们对我们的数据有一个更清晰的概念。在开始,我提到我们希望这个数据有列:发布日期、产品 ID、产品名称、包装类型、数量。Transf。和价格。我们将从重命名第一列开始。让我们从第一列开始。点击第一个标题上的插入符号,并选择编辑列- >重命名该列。这将显示重命名列的提示。
重命名第一列(作者图片)
我们也将对日期列进行同样的操作。我们将把该列的名称改为Post Date
。产品代码看起来像是保存了药品名称的数据,所以我们称之为Product Name
。列 Product/Name 包含药物的价格,因此我们将其重命名为Price
。Curr。成本价列保存售出的数量,因此我们将其重命名为Qty Transf.
。我们不需要运输。数量,转移。价值和剩余数量。我们将删除 Transf。数量和转移。首先通过点击标题上的插入符号并选择编辑列- >移除此列来获取值。我们可以将最后一列“剩余数量”重命名为Packing Type
。
重命名的列(作者图片)
我们已经重命名了列,但是它仍然不在需求的排列中。我们将从Product ID
开始。点击插入符号并选择**编辑列- >右移列。**这会将列移动到发布日期之后。
向右移动产品 ID(作者图片)
我们将通过单击标题上的插入符号将Price
列移动到工作表的末尾,选择编辑列- >将列移动到末尾。最后,我们将Qty Transf.
向右移动,就像我们之前对Product ID
所做的那样。
清理和重新排列后的标题(图片由作者提供)
删除不需要的数据
我们已经清理了标题,现在,我们清理数据。从第一行中,我们可以看到该行不合适,因为该行中没有产品名称、数量或价格数据。在我们的 6360 记录中有许多这样的行,我们必须清理它们。我们可以通过找到列中的空白单元格来做到这一点。我们将从产品名称开始。我们使用文本方面来获取空白单元格,就像我们对Post Date
列所做的那样。然后,我们单击(空白)值,只过滤列中的空白单元格。
产品名称的空白单元格(作者图片)
如果我们仔细观察过滤后的数据,我们会发现这些行是阳光药房不同分支机构的标题。我们不需要这些数据,因此我们将删除匹配的行。我们通过点击 All 列上的插入符号并选择Edit rows->Remove All matching rows来实现这一点。
删除与空白产品 id 匹配的行(按作者排序的图片)
这删除了 103 个不需要的记录,这是我们的方式负载污垢。让我们检查其他列,看看我们是否可以看到更多的空白。我们对Qty Transfer.
和Price
做同样的事情。对于Qty Transf.
,我们做了文本方面,我们注意到我们也有空白和一些应该有数字的列中的文本。检查后,我们看到文本也是数据中的标题,我们不需要,空白代表的行是为了显示每日总销售额,我们也不希望在这里。我们将删除它们,就像我们删除Product Name
列一样。
28 行匹配空白数量转换。单元格(作者图片)
26 行匹配数量转换中不需要的数据。专栏(作者图片)
对于Price
列,除了一个有趣的大数字之外,一切看起来都很好,这个数字代表了这个月的总销售额。我们不需要它,所以我们会像以前一样删除它。
删除代表总计的行(作者图片)
现在我们已经删除了所有不需要的行和列,一切看起来都很整洁。
清理数据集(图片由作者提供)
我们完了。这看起来真棒,你已经走了很长的路。您可能需要做一些调整,比如将负数改为正数,使用 GREL 将日期改为典型的mm/dd/yyyy
格式。我把它留给你去玩。
Open Refine 非常容易用来清理非常大的数据集,特别是如果你不是程序员或者不想经历用编程语言清理的恐惧。
我希望这有所帮助。感谢阅读。
使用基本命令进行数据分析:MySQL 工作台
学习如何使用 MySQL Workbench 创建和操作数据库
管理不同文件中的数据总是有风险的。这通常会导致不一致。一个组织无法通过维护成千上万的文件来有效地跟踪其业务活动。因此,数据库用于高效地访问和管理数据。 **DBMS(数据库管理系统)**软件在行业中广泛用于分析数据。
在本文中,我们将了解如何使用 MySQL Workbench 中的一些基本命令创建和操作数据库,并使用 SQL 语句分析数据。
使用 MySQL Workbench 创建数据库
在创建数据库之前,我们需要熟悉 DDL 和 DML 语句。
你可以从这里安装 MySQL。
SQL 中可用的命令大致分为两类:
- 数据定义语言
- 数据操作语言
作者图片— SQL 命令
数据定义语言(DDL) DDL 用于创建一个新的数据库以及修改一个现有的数据库。DDL 中可用的典型命令有创建、更改和删除。
创建数据库 我们将看到如何使用 MySQL Workbench 创建数据库。我们需要指定我们已经创建的数据库,因为 MySQL Workbench 不会自动选择我们新创建的数据库。
语法:
- 创建数据库<database_name></database_name>
- 使用<database_name></database_name>
通过使用上述命令,我们创建了一个“market_star_schema”数据库。
请注意,MySQL 中的每条语句都以“;”结尾
创建表格
现在我们有了一个数据库,我们将在其中创建组成表。我们将创建一个包含三列及其各自数据类型的表。
通过上面的代码,我们已经创建了三列。
Mode_of_Shipping
用数据类型作为字符类型Vehicle_name
用数据类型作为字符类型和Toll_Required
接受真或假,即布尔类型
更改表格
现在我们已经在数据库中创建了一个表,我们需要分配一个列作为主键。我们将在改变表格命令的帮助下完成。 Alter 命令用于修改现有的表或任何模式对象。
我们将Mode_of_Shipping
作为该表的主键。在上面的代码中,我们可以添加一列、移动一列等,而不是添加约束。除了主键,我们还可以添加外键、唯一键等。
下降表
要删除该表,我们必须使用 drop table 命令。请记住,一旦我们使用 drop 命令删除了表,就无法再次检索数据。
数据操作语言(DML) DML 用于处理数据集中出现的实际数据。DDL 中可用的典型命令有插入、更新和删除。
插入数据
插入命令用于将数据插入到列中。我们使用 insert into 命令选择数据库,同时使用 values 命令输入数据。
更新数据
现在我们已经将值插入到表中,我们可以在 update 命令的帮助下更新数据的现有值。
在上面的代码中,
更新命令用于选择我们想要更新数据的表格。
set命令用于选择我们想要改变数据的列。
使用命令的**,以便将上述改变的数据应用于该特定行。**
删除数据
我们可以使用删除命令删除数据。
在上面的代码中,
- 删除命令用于删除必要的数据。
- 来自命令的用于知道它必须从哪个表中删除数据。
- 使用 where 命令,删除特定列中所需的数据。
修改列
像 DDL 一样,我们可以在 alter 命令的帮助下在现有的表中添加另一列。
在上面的代码中,
- 在 alter table 和 add 命令的帮助下,我们创建了一个新列。
- 我们使用更新和设置命令来更新列的值
- 通过使用 alter table 和 drop column 命令,我们也可以删除列。
如果有任何差异,了解如何立即修改列以输入正确的数据是非常重要的。这样做,我们可以确保在分析数据时获得正确的见解。
在 MySQL 中查询
我们已经看到了如何创建、数据库和操作数据。现在,我们将看到如何使用 SQL 语句编写查询。
有 7 条 SQL 语句:
- 挑选
- 从
- 在哪里
- 分组依据
- 拥有
- 以…排序
- 限制
我们使用一个样本数据库‘market _ star _ schema’,可以从这里下载。
从中选择&
SQL 中的 SELECT 命令的主要功能是从我们的数据库中获取数据。
FROM 命令表示选择命令正在获取数据的表。
我们将从数据库中访问一个表,并使用 select 语句打印表上的所有内容。
在工作台中,输出看起来像这样,
打印数据库中的表—使用 Select 语句
打印列 要从表格中打印一列,我们必须提到列名而不是*。
现在输出将只有表中的客户名称,
打印表格中的列
打印多列 要打印表中的多列,我们必须在 select 语句中提到所需列的名称。
输出将是,
打印表格中的多列
如果我们在 select 语句本身中观察上面的输出,我们已经更改了列名,而不是显示默认名称。
Count
Count使用 select 中的 count ,我们可以打印该列中存在的行数。
输出将是总行数,
总行数
在哪里
Where 子句主要用于过滤掉我们从 Select 命令中得到的结果。为了从表中选择特定的数据,我们使用了 Where 子句。
假设我们需要在我们一直使用的表中查看有多少客户来自某个特定的州。这里,where 子句将发挥作用。
现在,这个州的顾客总数是,
打印使用的客户数量,其中
我们还可以在 where 子句中使用运算符。
输出将如下所示,
在 Where 子句中使用 AND 运算符
同样,我们也可以根据需要使用或>、<、运算符来代替和。
分组依据
要对表中某一列的值进行分组,我们使用 Group by。
让我们找出每个客户群中来自某个州的客户总数。
现在,输出看起来像这样,
使用分组依据的每个细分市场的客户总数
拥有
Having 子句用于对使用 group by 子句创建的组设置条件。
让我们从数据集中取出另一个表。
桌子看起来像这样,
市场 _ 事实 _ 完整表格
现在,让我们看看每个订单产生了多少利润。我们将根据Ord_id
列进行分组。
输出将是这样的,
每个订单 Id 的利润
现在,如果我们想要查看利润超过 1000 的订单 id,我们将使用 having 子句。
输出将只显示利润超过 1000 的订单 id
Having 子句
Having 子句始终位于 Group by 子句之后,并且必须位于 Order by 子句之前
以…排序
如果我们想要对一列或多列的值进行排序,我们将使用 Order by 子句。
假设我们想按字母顺序排列客户姓名。我们可以使用 order by 来实现。
输出将按字母顺序显示客户名称。
按字母顺序排列的客户名称
默认情况下,该顺序将按升序排列。如果我们在 order by 之后传递命令desc
,那么输出将按降序排列。
对于上面的相同代码,我们将在最后传递desc
命令。
输出将是,
按降序排序
限制
limit 用于限制输出将返回的行数。
让我们打印数据库中market_fact_full
表中订购最多的三种产品。
现在输出将只显示前三个订购的产品,
前三种产品使用限制
这些是必要的 SQL 命令,用于分析数据集中某个表的数据。
结论
本文展示了如何在 MySQL 中使用各种 DDL 和 DML 命令来使数据可供分析。
DDL 语句用于改变数据库结构,而 DML 语句用于改变其数据。
使用这七个命令, **SELECT,FROM,WHERE,GROUP BY,HAVING,ORDER BY,**和 **Limit,**我们可以对特定的表进行数据分析。
一旦我们掌握了这些命令,我们就可以使用内连接、外连接,创建视图和cte,一次对多个表进行分析。
感谢您阅读和快乐编码!!!
在这里查看我以前关于 Python 的文章
- 探索性数据分析(EDA): Python
- 假设检验:数据科学
- (CLT)中心极限定理:数据科学
- 推断统计:数据分析
- Seaborn: Python
- 熊猫:蟒蛇
- Matplotlib:Python
- NumPy: Python
参考
- 数据仓库:https://en.wikipedia.org/wiki/Data_warehouse
- 数据仓库:https://search Data management . techtarget . com/definition/Data-warehouse
- MySQL:https://www.tutorialspoint.com/mysql/index.htm
- MySQL 教程:https://www.w3resource.com/mysql/mysql-tutorials.php
使用 AWS 数据迁移服务(DMS)进行数据库迁移—一路走来的一些经验教训
Oracle 数据库到 Amazon Aurora PostgreSQL 的异构迁移
图片由 Pixabay 提供
最近,我们将一个相当大的内部 Oracle 数据库迁移到了 Amazon Aurora PostgreSQL。开始不同数据库平台之间的异构迁移从来都不容易。将此与将数据库迁移到云结合起来,无疑增加了挑战。
本文的目的是分享迁移方法,并强调我们遇到的一些问题和陷阱。
关于内部 Oracle 数据库
数据库版本: Oracle 企业版 12
数据大小: 1.6 TB
**最大的表大小:**90 亿行,超过 2000 个分区和子分区
迁移方法
(图片作者)
由于数据的大小相当大,我们决定不要让 AWS DMS 使用 VPN 连接从本地位置获取源数据。相反,我们选择了 Amazon EC2 上的一个临时 Oracle 实例。毫无疑问,从性能角度来看,这很有意义。
数据恢复
- 客户向我们发送了一个在内部创建的 Oracle 数据泵完整数据库导出(expdp ),并将转储文件复制到亚马逊 S3。转储是使用文件大小=64G 创建的
- 一旦转储文件被复制到亚马逊 S3,我们就在一个临时 Oracle 迁移实例上恢复这些文件。为此,我们在 AWS 上构建了一个m5a . 8x 大型 RHEL 7.6 实例。
- 数据恢复完成后,我们验证了本地 Oracle 数据库与 Oracle 迁移数据库之间的行数。
模式转换
我们使用 AWS 模式转换工具进行异构数据库迁移。这个工具工作起来非常顺畅。任何无法转换的对象都被清楚地标记出来,以便可以手动转换它们来完成迁移。假设您没有很多存储过程、函数和包,那么 AWS 模式转换工具将会转换您的大多数模式对象。
一些经验教训……
- Oracle 中的触发器代码迁移方式略有不同。触发器代码被转换成 PostgreSQL 函数,该函数又从 PostgreSQL 中的触发器调用。
- Oracle 中的数字数据类型被转换为 PostgreSQL 中的 double_precis ion。在正常情况下,这应该不成问题。然而,在数据迁移步骤中,我们确实遇到了数据截断问题。我们将在本文后面更详细地讨论这一点。
- 如果在列名中有一个保留字,那么这个名称就会用双引号括起来,比如“PRECISION”。不幸的是,没有简单的方法来标记这些列并预先修复它们。因此,创建一个脚本并根据 PostgreSQL 保留字列表验证列名是一个好主意。获得保留单词列表的一个简单方法是使用下面的 SQL:
SELECT * FROM pg _ get _ keywords()
模式验证
- 我们使用 pytest 框架进行模式验证。我们首先创建单元测试,用于比较常见的模式对象,如表、索引、约束、视图等。在目标数据库中。这个脚本每天都按计划运行,这样我们就能及时发现任何差异。
(图片作者)
吸取的一些教训…
- 我们错过了为 double_precision 问题添加验证源数据的单元测试。实际问题是在数据迁移阶段发现的,这并不好…对于下一次迁移,最好事先知道这个问题
- 我们还错过了为保留关键字添加单元测试。这个问题是在应用程序测试期间发现的,当时有些列用双引号括起来。最好预先标记这些列,并建议修改列名。
数据迁移
我们使用 AWS 数据库迁移服务将庞大的数据集从 Oracle 迁移到 PostgreSQL。
DMS 复制实例和 DMS 端点
一个 r4.4xlarge 实例。Oracle 和 PostgreSQL 各一个端点。
数据迁移任务
所有维度表都很小,因此我们创建一个 DMS 作业,一次性迁移所有这些表的数据。
对于最大的事实表,我们创建了多个 DMS 作业,每个作业复制 5-6 亿行。分割是使用如下选择过滤器完成的:
(图片作者)
一些经验教训……
- 数据迁移后,我们发现一些列的数据被截断。这些列的数据值大于 40 个精度值。这一次,我们使用 numeric(38,25) 执行了另一次数据复制迭代,但这没有帮助。最终,我们通过将这些列转换为源和目的地的 varchar i n、复制数据并最终在 PostgreSQL 中将这些列重置为 numeric 类型来解决这个问题
- 确保为复制实例提供足够的已分配存储,否则您的作业将运行非常缓慢,甚至会失败。我们最初使用默认的 50 GB 大小,但是作业开始变慢和/或失败。我们花了一段时间才找到问题的根源,但当我们将存储容量更改为 200 GB 时,所有作业都成功完成了。以下指标将清楚地向您展示在实施分配的存储更改后,写入和读取延迟下降的确切时间点…此后一帆风顺
(图片作者)
数据有效性
这是我们花时间最多的部分。我们的目标是比较 Oracle 和 PostgreSQL 的每一行数据。
我们首先创建了一个数据验证框架,它使用 JDBC 连接从 Oracle 表中获取数据。然后将每个块与 PostgreSQL 中相应的块进行比较。我们确实预料到 JDBC 方法会很慢,但是该框架在正确性和性能的测试迁移中工作得相当好。然而,在生产运行期间,由于数据量的增加,事情很快就变糟了。在某一点上,我们计算出框架需要一个月的时间来做比较…同样不好。
我们通过改变方法解决了上述问题。我们没有选择 JDBC,而是选择将 Oracle 和 PostgreSQL 表作为 Parquet 格式文件转储到亚马逊 S3 上。然后,我们编写了一个简单的 Pyspark 程序,使用 Datafames 执行比较。我们使用一个 EMR 集群启动了 Spark 程序,该集群有 1 个 m5.xlarge 主节点和 4 个使用 c4.8xlarge 点实例**的核心节点。**一个月的工作缩短到不到 1.5 天……还不错。
最后,Pyspark 脚本的结果……听起来很不错。查看 failed_count 列。
(作者图片)
希望这篇文章对你有所帮助。我希望它能在您的迁移过程中节省一些时间和烦恼。如果您需要 Pyspark 脚本,请随时 ping 我。我很乐意提供给你。
我希望这篇文章是有帮助的。AWS 数据迁移服务是由 Datafence Cloud Academy 提供的 AWS 大数据分析课程的一部分。课程是周末自己在网上教的。
数据库 101:数据科学家数据库简介
如何开始接触数据库世界?
图片由作者提供(使用 Canva 制作)
数据科学是快速发展的领域之一,我看不到它会很快放缓。我们对数据的依赖与日俱增。数据科学是关于数据的,收集它,清理它,分析它,可视化它,并使用它来改善我们的生活。
对于数据科学家来说,处理大量数据可能是一项具有挑战性的任务。大多数时候,我们需要处理和分析的数据比我们设备的容量(RAM 的大小)大得多。将信息存储在硬盘上可能会导致我们的代码变慢。
更不用说为了理解数据,并有效地处理数据,我们需要以某种方式对数据进行排序。这就是数据库发挥作用的地方。
数据库被定义为保存在计算机内存或云中的结构化数据集,可以通过多种方式进行访问。
作为一名数据科学家,在您将要从事的大多数项目中,您都需要设计、创建数据库并与之交互。有时您需要从头开始创建一切,而在其他时候,您只需要知道如何与已经存在的数据库进行通信。
当我第一次开始我的数据科学之旅时,处理数据库是最具挑战性的方面之一。这就是为什么我决定写一系列关于一切数据库的文章。
本文将对数据库进行简要介绍。什么是 SQL?我们为什么需要数据库?以及不同类型的数据库。
为什么使用数据库?
数据围绕着我们;我们日常生活中使用的一切都是基于海量的数据。你打开网飞,它会根据你之前的选择建议你接下来应该看什么。你打开 Spotify 应用;它告诉你根据你的喜好想要你可能喜欢的歌曲。
收集和分析数据是个性化我们每个人的体验的方式之一。这是一种打造适合所有人的产品的方式。
但是,
要做到这一点,需要将这些数据存储和组织在某个地方,某个易于访问、提供快速通信且安全的地方。
数据库使结构化存储变得安全、高效和快速。它们为如何存储、构造和检索数据提供了一个框架。有了数据库,您就不必在每个新项目中考虑如何处理数据了。
数据库的类型
图片由作者提供(使用 Canva 制作)
关系数据库
在关系数据库中,数据被组织和存储到可以使用某种关系相互链接的表中。例如,一家航空公司可以有一个所有航班的乘客表,还有一个特定航班的乘客表。航班代码可以连接这两个表。
作为开发人员和数据科学家,拥有连接表的这种能力使我们能够更好地理解表的不同元素之间的关系。理解这种关系可以给我们提示和洞察力,使分析和可视化数据的过程变得更容易。
与关系数据库通信和交互的方法是使用 SQL 语言。
非关系数据库
非关系数据库,也称为 NoSQL 数据库。这些数据库是通过类别而不是关系来连接存储在其中的信息的数据库。
NoSQL 数据库最流行的形式是键值对,你可以像对待 Python 字典一样看待它。键必须是惟一的,只要它们是惟一的,一个键-值对就可以在一个文档中存储所有的关系。
关系数据库使用表作为核心存储单元。数据库中的表由行和列的集合组成,您可以使用关系连接几个表。然而,在 NoSQL,数据存储在类似文档的存储设备上。只要知道文档的结构,您仍然可以执行所有日常任务,如添加、删除、更新数据。
结构化查询语言(SQL)
SQL 是一种功能强大的编程语言,用于在关系数据库管理系统(RDBMS)中操作数据。SQL 相对简单,却如此强大和高效。开发人员和数据科学家使用 SQL 在关系数据库上添加、删除、更新或执行特定操作。
SQL 不仅仅是对数据库执行简单的操作;它还可以用于设计数据库或对存储的数据进行一些分析。
为什么是 SQL?
SQL 非常受欢迎,通常广泛用于软件开发,尤其是数据科学,原因有很多,包括:
- 灵活性: SQL 允许您添加或删除新的列、表、重命名关系,并在数据库启动和运行以及进行查询时进行其他更改。此外,它可以轻松地集成到许多脚本语言中。
- **易用性:**学习 SQL 的基础知识既简单又直接。使用 SQL 不需要掌握令人困惑的隐藏提示语法。
- **没有冗余:**由于 SQL 的关系特性,您可以在同一个位置获得关于一个条目的所有信息,因此您不需要在所有表中重复相同的信息。
- **可靠性:**大多数关系数据库都可以导出和导入,使备份和恢复变得轻而易举。这些导出可以在数据库运行时执行,从而使故障恢复变得容易。
SQL 与非 SQL 数据库
每当你被分配一个新项目或试图设计一个 w 数据库,你可能问自己的第一个问题是*“我应该使用哪个数据库?SQL 还是 NoSQL?”。*
事情是这样的,当试图选择一个正确的数据库类型时,我经常参考 CAP 定理。CAP 定理描述了数据库的三个方面之间的关系:可用性、一致性和分区容差。
- **一致性:**这意味着对数据库的每次查询都应该返回最新的值。一致性有 5 个不同的级别,从强有力的即时结果到最终过时的结果。
- **可用性:**这意味着任何人都可以请求数据并得到响应,即使数据库的一项或多项出现故障。
- **分区容错:**一个分区是一个系统内的通信中断。容差意味着即使数据库各方面之间的通信中断,数据库也应该正常工作。
要选择一种数据库类型,您需要优先考虑 CAP 定理三个方面中的两个。如果您更关心一致性和可用性,那么您应该选择关系数据库。但是,如果您更关心可用性和分区容差,或者一致性和分区容差,那么 NoSQL 数据库将更适合您的项目。
图片由作者提供(使用 Canva 制作)
结论
数据是数据科学最关键的部分;没有数据就没有数据科学。对于任何数据科学家来说,设计、创建和交流数据库都是发展其职业生涯和丰富其知识库的必要条件。
数据库是一个广阔的领域;我无法在一篇文章中囊括所有内容。这就是为什么我决定将这个主题分成三篇文章,涵盖数据科学家应该了解的所有重要和必要的数据科学知识。
接下来的文章将涵盖数据库设计和交互的基础知识(SQL 介绍)。最后一篇文章将介绍 Python 中常用的数据库库,以及如何为您的数据和应用程序选择正确的库。
数据库 101: SQL 与 NoSQL:哪个更适合你的数据?
差异和最佳实践
图片由作者提供(使用 Canva 制作)
数据是数据科学所有子领域的支柱。无论你正在建造的建筑的规模或用途如何,你都需要获取和分析数据。通常,您需要的这些数据存储在 DBMS(数据库管理系统)中。
要与 DBMS 交互和通信,您需要使用它的语言或它能理解的语言。用于与 DBMSs 交互的语言是 SQL(结构化查询语言)。
近年来,数据库领域出现了另一个术语,即 NoSQL 数据库。如果您刚开始接触数据科学,您可能听说过 SQL 和 NoSQL 数据库。
但是,它们有什么区别,什么时候使用呢?
让我们为绝对的开始而开始。为什么我们有两种与数据库交互的方法?
简单、SQL 和 NoSQL 与不同类型的数据库交互。SQL 是用于与关系数据库交互的方法,而 NoSQL 用于与非理性数据库交互。
关系数据库
数据存储在关系数据库中不同的表中,每个表包含多个记录(行)。这些表使用一个或多个关系相互连接。
键定义了表之间的关系。一个键是包含每条记录的唯一值的表字段(列)。如果一个字段被定义为一个表的主键,这个字段可以包含在多个表中,并且可以用来同时访问不同的表。一旦使用主键将其表连接到另一个表,它将在另一个表中被称为外键。
例如,下图显示了航空公司数据库的一部分。我们有两张表,飞行员表和航班表。这两个表被连接起来,用作飞行员表“PilotId”中的主键我可以使用飞行员的 Id 来访问飞行员表中关于该飞行员的信息,以及该飞行员正在处理的航班。
图片由作者提供(使用 Canva 制作)
因此,在飞行员表中,PoilotId 是主键,而在 flights 表中是外键。PilotId 在这里用于形成两个表之间的关系。
非关系数据库
与关系数据库不同,非关系数据库(NoSQL 数据库)不在表和记录中存储数据。相反,在这些类型的数据库中,数据存储结构是为特定需求而设计和优化的。
与关系数据库使用的 SQL 不同,NoSQL 数据库使用对象关系映射(ORM)来促进与其数据的通信。
NoSQL 数据库的四种流行类型,面向列、面向文档、键值对和图形数据库。这些类型可以单独使用或组合使用。选择将取决于您的应用程序和您需要存储的数据类型。
面向列的数据库
顾名思义,在面向列的数据库中,数据以列的形式存储和组织。如果需要存储稀疏数据,这种类型的数据库非常有用。稀疏数据更趋向于面向列的数据组织方法。
面向文档的数据库
在面向文档的数据库中,排序的数据的结构不需要很严格。它是文档结构中字段和数据值的集合。这些面向文档的数据库通常存储为 JSON 字符串,可以使用 YAML、XML 或纯文本编码来保护数据。
使用面向文档的数据库的一个好处是,您不需要让所有的文档都使用相同的结构。这给了开发人员在同一个数据库中对不同数据类型进行排序的自由。在 Python 中,MongoDB 是面向文档的数据库的一个例子。
键值数据库
如果你熟悉 Python,你可以把键值数据库想象成一个 Python 字典。数据库中的每个数据对象都将被存储为一对键和值。
图形数据库
当您的数据高度互联时,您将需要使用一个允许您高效实现这一点的数据库。图形数据库被认为是最复杂的 NoSQL 数据库。然而,它非常通用,这使得它非常适合许多应用程序。
图片由作者提供(使用 Canva 制作)
如何在 SQL 和 NoSQL 之间选择?
那么,我们如何在 SQL 和 NoSQL 数据库之间做出选择呢?
为了回答这个问题,你需要考虑 4 个方面:灵活性、可伸缩性、一致性和可用的技术。
- **灵活性:**有时候,当你的数据有不同的结构和不同的类型。根据定义,NoSQL 数据库给你更多的自由来设计你的模式和在同一个数据库中存储不同的数据结构。另一方面,SQL 数据库具有更严格的结构和模式。
- **扩展性:**你见过日本车停车电梯吗?它可以让你把车一辆挨着一辆停放。现在,我想让你问问自己,增加电梯层数和建造新的电梯哪个效率更高? SQL 数据库是垂直可伸缩的,这意味着你可以增加它的级别(增加它的负载)。虽然 NoSQL 数据库是水平可伸缩的,但是您可以通过将工作分配给多个服务器来增加其负载。
- 一致性 : SQL 数据库拥有高度一致的设计。然而,基于 DBMS,NoSQL 数据库可以是一致的,也可以是不一致的。比如 MongoDB 是一致的,而 Cassandra 这样的数据库就不是。
- 可用技术:您可能会考虑的一个方面是数据库技术的当前发展阶段。因为 SQL 数据库已经存在了很长时间,所以它比 NoSQL 数据库发展得更快。所以,对于初学者来说,从 SQL 开始,然后转移到 NoSQL 可能是最好的选择。
根据经验,如果您正在处理 RDBMS(关系数据库管理系统),想要分析数据的行为或想要构建定制的仪表板,SQL 是更好的选择。此外,SQL 通常允许更快的数据存储和恢复,并且更好地处理复杂的查询。
另一方面,我们有 NoSQL 数据库,如果您想扩展 RDBMS 的标准结构,或者您需要创建一个灵活的模式,这是更好的选择。当您存储的数据和日志来自分布式来源,或者您只需要临时存储时,NoSQL 数据库也更好。
外卖食品
最后,我不能说 SQL 绝对比 NoSQL 好,或者相反。它们每一个都有自己的优点和缺点,您的选择将基于您的数据、您的应用程序以及什么使开发过程对您来说更容易。
SQL 数据库更古老,因此研究得更多,也更确定了固定的模式设计和结构。由于其灵活的模式,NoSQL 数据库易于扩展、灵活且使用相对简单。
那么,您的数据需求是什么?你的数据结构良好吗?您正在处理大量数据吗?
永远听从你的数据,你会做出正确的选择。
数据库:概述
第 2 部分:MongoDB 和 HBase 分布式文件系统的底层架构以及 Python 中的数据库操作
在本文中,我们将讨论当今世界提供大数据解决方案所基于的架构,即分布式文件系统,并了解它们实际上是如何实现的。在本系列的第 1 部分中,我们已经讨论了基本的数据库概念和安装过程。作为先决条件,请随意检查。
MongoDB 和 Hbase 都是分布式 NoSQL 数据库,广泛用于处理大型数据问题。让我们进入架构和实现细节。
MongoDB
MongoDB 是一个基于文档的 NoSQL 数据库。它不需要固定的模式定义。Mongo DB 将数据存储为二进制 JSON 或 BSON。它支持水平缩放。几个服务器实例组成一个集群来支持 Mongo DB 作为一个分布式系统。
MongoDB 使用 MongoDB 查询语言,并支持即席查询、复制和分片。分片是 MongoDB 的一个特性,有助于它作为分布式数据系统运行。让我们看看 MongoDB 是如何实现这些特性的。
Mongo 中的复制
复制是一项非常重要的功能,可以防止一台服务器上的数据丢失,提高数据的可用性,并提供故障保护。
MongoDB 使用概念副本集实现复制。副本集是一组托管相同数据集的 mongod 实例。选择其中一个节点作为主要节点。这称为主节点。所有其他节点称为次节点。主节点接收来自用户的所有操作,并且通过使用相同的操作从主节点更新辅助节点以保持一致性。如果主节点关闭,则选择一个次节点作为主节点,并继续执行操作。当故障节点恢复时,它作为辅助节点加入集群。我们可以使用 mongo Atlas 来控制我们的 Mongo 实例集群。 Mongo 集群是基于水平扩展和添加实例的思想创建的。
副本集示意图:作者提供的图像
Mongo DB 中的分片
MongoDB 使用分片来跨多台机器存储数据。它使用水平扩展来添加更多的机器,以根据负载和需求的增长来分发数据和操作。
MongoDB 中的分片安排主要有三个组件:
- **碎片或副本集:**每个碎片充当一个单独的副本集。他们存储所有的数据。他们的目标是提高数据的一致性和可用性。
- **配置服务器:**它们就像集群的管理者。这些服务器包含集群的元数据。他们实际上拥有集群数据到碎片的映射。当查询到来时,查询路由器使用来自配置服务器的这些映射来定位所需的碎片。
- **查询路由器:**查询路由器是作为用户应用程序接口的 mongo 实例。它们接受来自应用程序的用户查询,并向应用程序提供所需的结果。通常,每个集群有多个查询路由器用于负载分布。
作者图片
上图展示了 MongoDB 的分片安排。尽管该映像只有 2 个查询服务器和分片,但实际集群中通常有更多,尽管默认情况下集群中有 3 个配置服务器。
我们上面谈到的思想是 MongoDB 操作及其分布式数据系统架构背后的两个最重要的思想。
现在,让我们看看 Apache HBase 是如何实现分布式系统的思想的。
Apache HBase
Apache HBase 是一个基于列值的 NoSQL 数据库。它基本上存储了基于表或模式的 MySQL 数据库所存储内容的转置。不同的行或记录有不同数量的列或字段。在操作过程中,可以在任何地方插入或更新列。该模式是完全动态的,因此不需要预先声明。最适合非结构化数据。它是水平可伸缩的,特别适合稀疏数据。
HBase 实际上是为处理海量数据而设计的,广泛用于社交媒体运营,每天都会产生大量数据。因此,HBase 通常用于集群中至少有 5 台服务器,并且复制系数至少为 3 的情况。
Apache HBase 是使用 MapReduce 和 Google FileTable 背后的思想开发的,作为一个由 Apache 保护伞支持的开源数据库。Apache HBase 使用了几个有趣的概念,作为领先的技术巨头使用的其他数据库的基本思想。
MapReduce
MapReduce 是一个框架,它的目标是以一种更快、更好维护的方式处理大量数据。它还打算引入并行访问,以便加快速度。MapReduce 的思想主要包含两个部分:映射和简化,正如它的名字所描述的那样。
映射部分由称为映射器的组件执行。映射器检查数据库中插入的每一行数据,并将它们分解成一种键值对。因此,它接收原始输入数据并创建更小的数据块。这是第一阶段。
还原部分基本包含洗牌和还原两个部分。这些操作由称为减速器的部件来完成。reducers 的功能是将映射器的输出进一步分解成更紧凑的键值对。Reducers 的输出存储在底层文件系统中。
输入数据进入文件系统,从那里它被发送到映射器,然后到缩减器。缩减器的输出被保存回文件系统。文件系统中有控制转发流量和网络流量的主节点。
整个系统是用 JAVA 开发的。
MapReduce 架构:作者图片
Hadoop 文件系统
HBase 使用 Hadoop 文件系统作为底层架构。Hadoop 文件系统是由 Apache 开发人员在 Google 的文件表论文中提出这个想法后构建的。让我们检查一下文件系统架构的工作基础。
作者图片
上图描述了 HBase 底层的 Hadoop 文件系统。它有一些基本组件:
**Namenode:**Namenode 是一个包含 Hadoop 集群元数据的 Linux 系统。它管理客户端数据访问,也管理文件系统的命名空间。
**数据节点:**数据节点是 Linux 系统,它根据用户或客户端的请求对数据进行读写指令,并根据 Namenodes 的请求进行创建、删除和复制。
系统中还有其他重要部分,如 Jobtracker 和 TaskTracker。在启动 Hbase 之前,我们需要运行 HDFS 系统,并使名称和数据节点联机。
让我们看看 HBase 的架构组件:
HBase 架构
作者图片
上图显示了 HBase 的架构。它主要包含两个主要部分:
- HMaster :组件不存储数据。它是一种控制器。它控制 HRegion 服务器和客户端请求。它有元数据,充当集群的主节点。
- **HBase 客户端:**这是 HBase 通过其与应用程序进行交互的组件。
- HRegion Server: 这个组件实际存储数据。一个集群有多个 HRegion 服务器。数据基于块分布在多个 HRegion 服务器上。
作者图片
因此,基本上,插入的数据块被分解成块,这些块分布在 HRegion 服务器中,并由集群的 HMaster 管理。
读/写架构
写作:
作者图片
在 HBase 中,写操作如上图所示。HBase 创建一个名为 Memstore 的有限内存缓存。客户端在 Memstore 中写入。现在,由于内存有限,Memstore 很快就满了。每当 Memstore 完全填满时,就会创建一个 Memstore 快照并保存为 HFile。HFile 随后被转移到磁盘上进行永久存储。Memstore 是临时存储器。因此,如果出现故障,可能会丢失数据。为了防止 Hbase 维护称为 WAL 或预写日志的东西。它是保存在光盘中的记录或日志。如果一些记录丢失了,就从磁盘上的 WAL 中检索出来。
阅读:
作者图片
阅读就是这样做的。一旦内存存储的快照保存为 HFile,内存存储就会被刷新。因此,必须搜索所有的 HFile 和光盘来获取信息。这就导致了大量的时间消耗。因此,为了节省时间,创建了称为块缓存的东西来保存频繁访问的信息。因此,首先搜索 Memstore 来访问数据,然后在失败时,搜索块缓存。之后,搜索 Hfiles。
更新和删除
更新和删除不是在客户端传递命令的瞬间完成的。这些命令被保存为标志、更新标志或删除标志。Hfiles 是不可变的,也就是说,一旦写入,就不能更改。因此,当这些 Hfiles 被合并以写入光盘时,这些值被更新或删除。因此,为了访问数据,HBase 还需要检查 Hfiles,以在返回查询结果之前查看是否有这样的标志。
我们已经讨论了 HBase 的所有整体思想和概念。
我们看到的 Hbase 和 MongoDB 的概念是大多数当前 NoSQL 数据库使用的一般概念。
用 Python 实现
让我们看看 python 如何使用和访问数据库。首先,我们需要了解 MySQL、MongoDB 和 HBase 之间的基本结构差异。
MySQL 在最顶层有数据库。在第二层,有表格。在最低级别或最后一级,有记录或行。所以,每个数据库都有表,每个表都有记录
MongoDB 有数据库。每个数据库都有集合而不是表。每个集合都有最低层的文档,描述键值对。
HBase 的最高级别只有表。然后它有行索引或索引,就像每个记录的主键。要在 HBase 中执行任何操作,我们需要知道必须是唯一的行或记录 id。HBase 也有柱族的概念。它没有固定的模式,但是列族有助于全面了解表的数据记录中的列。每个表只能有一个列族。
MySQL:
实现 MySQL-python 和 mysql-connector-python 是为了从 python 提示符或使用 python 代码访问正在运行的 MySQL 数据库。
MySQL-python 可以从 这里 安装。
mysql-connector-python 可以从这里的安装。
语法:
关系
**import** **MySQLdb**
**import** **mysql.connector**
conn= mysql.connector.connect(host="localhost",user="abhijit",passwd="1234",db="users" )
mycursor = conn.cursor()
插入:
mycursor = conn.cursor()
mycursor.execute('INSERT INTO user_details (id,email,password) VALUES("**%s**","**%s**","**%s**")'%(id1,email,passwd))
conn.commit()
查询:
query="""SELECT * FROM user_details WHERE email='**%s**'"""%(email)
mycursor = conn.cursor()
mycursor.execute(query)
dup=mycursor.fetchall()
i=mycursor.rowcount
MongoDB
PyMongo 库用于从 Python 提示符访问 MongoDB。
pymongo 库可以从这里的 安装。
Pymongo 的官方教程可以在这里 找到 。
语法:
连接:
**import** **pymongo**
**from** **pymongo** **import** MongoClient
client = MongoClient()
client = MongoClient('localhost', 27017)
db_mongo = client['user_connections'] #selecting database
m_user_recs= db_mongo['user_records'] #selecting collections
插入:
data={
'c_id':'abhi',
'connections':['123','myac.a','abhir'],
'posts':[]}
m_user_recs.insert(data)
因此,我们可以在 mongo 文档中插入任何数据类型。它可以是列表,甚至是子文档。
查询:
recs=m_user_recs.find({"c_id":id1}) #(1)
f**or** r **in** recs:
frnds=r['connections'] #(2)
查询(1)返回字段“c_id”的值为 id1 的文档。(2)代码片段从返回的文档中选择“连接”字段。
更新:
myquery = { "c_id": id1 }
new_val={"$set": { "req_sent": cons }}
m_user_recs.update(myquery, new_val)
该查询将“req_sent”字段的值设置为由变量“cons”给出,其中字段“c_id”具有由变量 id1 给出的值。
HBase
HappyBase 库用于从 Python 访问 Apache HBase。
Happybase 可以从 这里 安装。
Hbase 的官方教程是 这里是 。
$ create 'table_name', 'column-family'
上述语法可用于从 HBase shell 创建 HBase 表。
语法:
连接:
**import** **happybase**
conn=happybase.Connection('localhost')
table=conn.table('users')
插入:
table.put(id_u, {b'cf_user_1:name': record[1],b'cf_user_1:from': record[2],b'cf_user_1:Education': record[3],b'cf_user_1:Profession': record[4],b'cf_user_1:location': record[5],b'cf_user_1:birthday': record[6],b'cf_user_1:profile_pic': record[7]})
上述语法可用于从 python 插入 HBase 表。这里的“id_u”是具有行键的变量。b’cf_user_1 ‘是列系列,而’ name ‘、’ from '是行的字段。
查询:
row_f=table.row("Roy Key")
loc=(row_f[b'cf_user_1:location'])
fr=(row_f[b'cf_user_1:from'])
edu=(row_f[b'cf_user_1:Education'])
代码片段的第一行可以访问该行。接下来的几行访问相应的字段。
我们已经看到了这些库以及它们在 python 中的相应用法。
结论
在当前世界中,随着社交媒体网站和云的概念日益发展,大数据的概念越来越受到关注。每天都有大量的数据上传到云端。所以,我们已经越过了这个点,数据量可以由世界各地的一百或一千台计算机来处理。现在,分布式系统将会越来越受欢迎。像 Cassandra、FileTable、CouchDB 和 Hadoop 这样的数据库开始被 Linkedin 和脸书这样的普通和最大的社交媒体网站所使用。
在本文中,我们已经看到了 python 中的概念及其工作方式和库。如果你想要一个工作实例,请在这里 找到我的 GitHub 库 。
希望这有所帮助。
数据库:概述
入门
第 1 部分:概念和安装:MySQL、HBase、MongoDB
在当今世界,我们必须处理大量的数据,并以一种有利的方式存储这些数据。如今,每天都有大量的数据来自脸书和 Twitter 等社交媒体网站。以前,我们主要处理结构化数据,即可以包含在表格结构中的数据,因此,我们在所有情况下都使用 MySQL。在当前的场景中,首先,数据是以非结构化的方式获取的,并且需要以非结构化的方式存储;其次,数据是以海量的方式获取的。因此,不可能在一台服务器上存储一个数据库的全部内容,需要同时访问多台服务器。当前的数据库还需要容错,即如果一个数据库服务器由于某种原因出现故障,数据不会丢失,并且如果该服务器上的数据被用户访问,其他服务器会响应请求。
所有这些原因导致了 NoSQL 和分布式数据库系统的设计。目前,Oracle、PostgreSQL、Microsoft SQL services 等 SQL 数据库被广泛用于处理结构化数据,而 MongoDB、Hadoop、Amazon 的 DynamoDB 和 Hbase 等 NoSQL 数据库被用于处理非结构化数据。
属性和概念
如今,我们广泛使用 SQL 和 NoSQL 数据库。它们没有一个比另一个更好,它们是根据情况的要求来选择的。NoSQL 数据库支持变量模式,因此在声明期间不需要模式定义。它们最适合动态数据。SQL 数据库需要模式定义,但是拥有一种结构化语言并具有像 JOIN 这样的属性,易于使用并与复杂查询兼容。
让我们检查一些重要的概念。
原则:SQL 和 NoSQL 都遵循一些原则。它们是:
酸性
- 原子性:SQL 数据库上的事务或操作要么完全执行,要么根本不执行。
- 一致性:在 SQL 数据库上执行操作或事务前后,数据库的状态保持不变。例如:A 在银行有 2000 单位的存款,B 有 1000 单位,总数是 3000。现在,如果 A 转账 500 给 B,同样在操作之后,总额保持不变。这就叫一致性。
- **隔离:**该属性确保即使几个事务同时发生,所有的事务都是互斥的,换句话说,是隔离的
- **持久性:**该属性确保一旦事务被提交,它就被保存并且不再被修改
上限理论
- **一致性:**表示服务器网络中存储相同数据的所有节点读取最近写入的值,并相应地进行更新。
- 可用性:它声明每个请求都应该收到一个响应,无论是成功还是失败,并且它可以处理多个请求。
- **分区容差:**表示数据库成功运行,没有数据或消息丢失或系统的任何部分出现故障。
缩放
伸缩的概念在分布式系统的开发中起着巨大的作用。扩展是一种系统,它允许服务器不断发展,以应对不断增长的数据量。主要有两种方式。第一个是垂直缩放。这个概念以前使用过。这个概念表明,我们一直使用一个实例,并随着数据负载的增加而更新实例的大小和性能。这个过程非常昂贵,但易于实施。一些 SQL 数据库使用垂直缩放
第二个概念是水平缩放。一些 NoSQL 数据库,如 MongoDB 和 CouchDB,使用水平伸缩。分布式系统是使用这个概念实现的。创建了几个服务器计算机集群。每台服务器计算机称为一个实例。水平扩展意味着我们应该向集群添加更多的实例来处理更多的数据。
复制
复制的概念是当前分布式数据库系统中另一个非常重要的概念。来自一个数据库服务器的数据被复制到其他副本服务器。因此,数据是分布式的。这一概念创建了备份并提高了可用性。在 MongoDB 的例子中。服务器中的数据分布在该集群中的其他服务器中。其中一台服务器充当主服务器,其他服务器充当副本服务器。如果主服务器出现故障,将选择其中一个副本服务器作为主服务器。一旦故障服务器保持运行,它将作为副本加入群集。在数据更新的情况下,主服务器从应用程序获取更新,然后更新的数据与所有副本同步以保持一致性。
NoSQL 数据库:类型
NoSQL 不仅代表 SQL。非结构化数据是指不能以表格方式存储的数据。设计了几种 NoSQL 方法来处理这些类型的数据。其中最常见的是:
**文档数据库:**这些数据库以 JSON 格式保存数据。他们使用键值对。它们是可定制的,最适合动态数据。每个键可能有也可能没有相同数量的字段。例如:MongoDB 和 CouchDB。结构:
**列数据库:**这些数据库将数据写入列而不是行。每一行都有一个特定的行 id。这里的每个操作都是使用行 id 执行的。这种类型的数据库背后的想法是,每条记录可能不包含所有列的值。因此,我们修复 row_id 并按列输入数据。每条记录的列数可能相同,也可能不同。比方说,在 facebook 注册中,需要很多数据。不同的用户填写不同数量的字段,在这种情况下,基于列的数据库广泛用于仅存储输入的数据。例如:Apache Cassandra、Apache Hbase
对于基于列的结构,我们需要为表定义一个列族。它类似于表定义的一部分,尽管它并不严格。
**键值存储:**这些类型的数据库工作起来像哈希函数或哈希表,它们是不可定制的。例如:Redis
**基于图形的数据库:**这些数据库把每一条记录看作一个节点,把值看作节点的特征。例如:Neo4J
在系列文章中,我们将讨论三个最常用的数据库:MySQL、MongoDB 和 HBase 以及它们在 python 中的实现。
安装
我用的是 Ubuntu 18.04 系统。我正在为 ubuntu 系统提供安装。
MySQL
它是一个关系数据库。它是一个免费的发行版,由 oracle 提供支持。它可以独立安装并从终端使用,也可以使用 PHPMyAdmin。对于第二个选项,需要安装 apache 服务器,或者可以通过 LAMP (Linux、Apache、MySQL、PHP/Python/Perl)堆栈应用程序(如 XAMPP)使用。
Xampp 应用程序
对于 MySQL 安全安装。执行给定的步骤:
$ sudo apt update
$ sudo apt install mysql-server
$ sudo mysql_secure_installation
这些步骤将以安全的方式安装 MySQL。最后一步将让您创建安全用户并为他们设置密码。
MongoDB
MongoDB 是使用最多的 NoSQL 数据库。它的工作原理是分布式数据库系统。我们可以使用下面给出的步骤在我们的系统上设置一个单一的机器集群数据库。MongoDB 是一个文档数据库,使用键值对。该安装仅适用于 ubuntu 18.04。对于其他版本,相应的 Ubuntu 版本是不同的。安装步骤:
$ wget -qO - [https://www.mongodb.org/static/pgp/server-4.4.asc](https://www.mongodb.org/static/pgp/server-4.4.asc) | sudo apt-key add -
$ echo "deb [ arch=amd64,arm64 ] [https://repo.mongodb.org/apt/ubuntu](https://repo.mongodb.org/apt/ubuntu) bionic/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
$ sudo apt-get update
$ sudo apt-get install -y mongodb-org
以上代码为相应的发行版安装了最新版本的 MongoDB。
要启用或启动 mongo:
$ sudo systemctl status mongodb
$ sudo systemctl mongodb start
MongoDB 通常在本地主机和端口 27017 上运行。启动 MongoDB 的大多数错误都是在端口上运行其他操作时发生的。MongoDB 创建一个“data”文件夹来保存 Mongo 的数据和元数据。有些错误是由于无法访问数据文件夹而引发的。
第一个错误可以使用以下命令来纠正:
$ ~ netstat -an | grep 27017
这将列出端口上所有活动的进程。您需要终止这些进程并重新启动 mongo。
对于第二个错误,我们需要在外部创建 data 文件夹,并让 mongo 使用它。步骤:
$ cd /Users
$ cd home
$ mkdir data
$ cd data
$ mkdir db
$ mongod --dbpath ~/data/db
重启 mongo,我们就可以开始了。
通常在重启 mongo 服务时会停止。在进行调试步骤之前,请检查 mongo DB 的状态,如果没有运行,请重新启动它们。
我们可以使用 Mongo Compass 来使用 Mongo 的 GUI 版本。这里的是免费且容易获得的。
HBase
HBase 是一个 NoSQL 数据库。这是一个基于列的数据库。它用于非结构化数据,并且是可伸缩的。HBase 是一个由自由分布的数据库驱动的 apache。它也可以使用系统集群,但是我们可以创建一个单独的系统集群。
HBase 在底层使用 Hadoop 数据库文件系统,所以我们需要先安装 Hadoop,它也可以在 java 上工作,所以我们需要安装 Java 来操作 Hbase。
因此,要安装 Hadoop,请遵循以下步骤:
$ sudo apt update
$ sudo apt install openjdk-8-jdk -y
$ java -version; javac -version
这些命令将安装 java,最后一行将提供安装的 Java JDK 的路径和版本。我们需要拯救这条路。
接下来,开始步骤:
sudo apt install openssh-server openssh-client -y
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
ssh localhost
这些步骤将允许用户连接到本地主机。
接下来,进入 Hadoop 的官方页面,选择版本并下载二进制版本。这可以手动完成,或者我们可以使用“wget”命令来安装。对于版本 3.2.1,我们可以使用代码片段
**wget** [**https://mirrors.estointernet.in/apache/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz**](https://mirrors.estointernet.in/apache/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz)
我们的 Hadoop 将被下载。
为了安装,我们需要配置 Hadoop 文件和 Bash 来更新环境变量。按照步骤进行配置
$ sudo gedit .bashrc
在 Bashrc 中粘贴以下行:
export HADOOP_HOME=/home/abhijit/hadoop-3.2.1
export HADOOP_INSTALL=$HADOOP_HOME
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/binexport JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$PATH=$JAVA_HOME/bin
这些只是环境变量和下载路径。请根据您的下载位置进行检查。如果出现错误,请相应地更改 Hadoop 主路径,因为该文件夹保存在您的系统上。要让更新后的 bash 工作,请使用:
$ source ~/.bashrc
接下来,使用
$ cd hadoop-3.2.1
$ cd etc
$ cd hadoop
$ ls
在这里,我们必须更新文件:
- hadoop-env.sh
- 核心网站. xml
- hdfs-site.xml
- mapred-site-xml
- yarn-site.xml
因此,使用“gedit”打开每个文件,粘贴相应的行并进行更改。
hadoop-env.sh
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
该行存在,但被注释掉了。我们只需要取消注释并进行修改。我们必须确保路径与我们保存在 bash 文件中的路径相同。
core-site.xml
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/abhijit/tmpdata</value>
</property>
<property>
<name>fs.default.name</name>
<value>hdfs://127.0.0.1:9000</value>
</property>
</configuration>
请相应地更新值部分。我在用我的分机。这些文件在安装时自动创建。如果未创建“tmpdata”文件夹,请手动创建并更新路径
$ mkdir tmpdata
hdfs-site.xml
<configuration>
<property>
<name>dfs.data.dir</name>
<value>/home/abhijit/dfsdata/namenode</value>
</property>
<property>
<name>dfs.data.dir</name><value>/home/abhijit/dfsdata/datanode</value>
</property>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
该文件包含基本的 Hadoop 文件系统配置。
mapred-site-xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>127.0.0.1</value>
</property>
<property>
<name>yarn.acl.enable</name>
<value>0</value>
</property>
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PERPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
</property>
</configuration>
保存所有文件,我们就可以开始了
接下来,返回“hadoop-3.2.1”主文件夹,使用以下命令:
hdfs namenode -format
这将格式化创建的 namenode 文件夹。
接下来,使用:
$ cd sbin
$ ./start-all.sh
最后一个命令启动所有服务。
运行后,它将看起来像:
我们可以使用“jps”命令来列出正在运行的守护进程
现在,我们准备安装 HBase。
要安装,我们可以使用 wget 命令,也可以从下载 URL 手动下载
我使用过 HBase-2.2.6,使用:
wget [http://www.apache.org/dyn/closer.lua/hbase/](http://www.apache.org/dyn/closer.lua/hbase/)[hbase-2.2.6-bin.tar.gz](https://mirrors.estointernet.in/apache/hbase/2.2.6/hbase-2.2.6-bin.tar.gz)
如果您是手动下载,请将其粘贴到主目录中。
接下来,在 Hbase 中,我们还需要进行一些配置。我们需要在环境变量中添加 Hbase 路径:
$ gedit .bashrc
然后,我们需要粘贴这些行来更新环境变量:
export HBASE_HOME=/home/abhijit/hbase-2.2.6
export PATH=$PATH:$HBASE_HOME/binNow, close the file and use *source ~/.bashrc*
我们需要去 conf 文件夹。
$ cd hbase-2.2.6
$ cd conf
在 conf 中,我们需要打开“hbase-env.sh”文件,并粘贴下面给出的行,就像我们在前面的例子中所做的一样:
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
接下来,我们需要更新 hbase-site.xml
hbase-site.xml
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.tmp.dir</name>
<value>./tmp</value>
</property>
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>localhost</value>
</property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2181</value>
</property>
<property>
<name>hbase.rootdir</name>
<value>hdfs://127.0.0.1:9000/hbase</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name><value>/home/abhijit/zookeeper</value>
</property>
</configuration>
请相应地注意“tmp”和“zookeeper”文件夹的文件位置。
现在,我们可以走了。
我们需要转移到“hbase-2.2.6/bin”并使用。/start-hbase.sh 启动服务。
$ cd hbase-2.2.6/bin
$ ./start-hbase.sh
在这里,我们可以看到 HMaster、HRegionServer 和 HQuorumPeer 正在运行。这表明我们的 HBase 服务器已经启动并正在运行。
我们可以使用 HBase shell 来访问我们的 HBase:
通常 Hbase 在端口 9000 上运行。
如果我们想用 python 访问 Hbase,它有一个‘happy base’库。它使用节俭网关访问 Hbase。为此,我们还需要在 9090 端口上运行 thrift,使用:
hbase thrift start -p 9090
我们也将能够看到我们的节俭服务器运行。我们现在可以使用 Hbase 了。
结论
在本文中,我们已经了解了如何安装数据库以及数据库中的一些基本概念。本系列的第 2 部分讨论了 python 中的概念和工作示例。
希望这有所帮助。
fastai 中使用 Lego Minifigures 数据集的数据块 API 和图像分类
我可以一整天都这样——史蒂夫·罗杰斯
本帖涵盖的主题如下
您可以点击上面的任何主题,导航到相应的部分
介绍
图像分类自古以来就是一项非常常见的任务,然而直到深度学习之后,计算机才能够熟练地完成这项任务。随着卷积神经网络的出现,这项任务变得如此出色,以至于近年来计算机在一些分类应用中也击败了人类。建立一个模型来进行图像分类(MNIST 数字识别)标志着许多初学者深度学习之旅的开始。因此,让我们做同样的事情,只是让它变得更令人兴奋,通过使用一个在 Kaggle 上策划的数据集,叫做乐高迷你人物分类。
由杰瑞米·霍华德和西尔万·古格开发的 fastai 是一个基于 PyTorch 构建的库,用于深度学习实践者简化构建/训练和从 DL 模型进行推断的过程。用相对较短的代码,您可以为几乎所有的任务(分类、回归(结构化和非结构化数据)、协作过滤等)建立最先进的模型。)使用这个库;这就是制作它所付出的努力。所以让我们充分利用它,从图像分类这个任务开始。
任务
我们有 27 个由乐高建造的不同迷你人物的图像,这些图像是从 Kaggle 这里获得的。我们必须建立一个分类器,当给定一个特定的迷你人物的图像时,它可以告诉哪个超级英雄/角色。让我们读入数据集,看看其中的几个条目。
图片由 Vinayak 提供
正如我们所看到的,索引文件保存了加载需要提供给模型的数据所需的信息,元数据包含了关于不同类的信息。
当我们仔细观察迷你人像时,可以观察到 class_id 1 和 class_id 17 都代表蜘蛛侠。id 17 中的蜘蛛侠是漫威超级英雄系列中的一个,因此被相应地重新命名为漫威蜘蛛侠。一旦完成,我们就可以将 class_id 上的索引和元数据文件作为主键连接起来。
此外,数据块 API 期望列 train-valid 是一列布尔值,如果该行属于验证集,则该列的值为 true,否则为 false。因此也进行了更改,完成所有这些后,最终的数据帧如下所示。
图片由 Vinayak 提供
让我们分别看看训练集和验证集中的图像数量。一般来说,它们的比例相等是好的,而且它们应该属于同一个种群。让我们看看数据的分布情况。
图片由 Vinayak 提供
数据集看起来非常平衡,在训练集和验证集中各有近 150 个元素。嗯,关于图像标准,这个数字对于训练神经网络分类器来说是相当低的。当有大量图像时,深度神经网络学习良好的表示函数。相对于正常的深度学习标准,每个分类标签有数百或数千张图像是非常正常的。在这里,我们有 27 个类的 300 多张图片,这意味着我们每个类的图片不超过 10-12 张。让我们看看使用这些数据可以建立多好的模型。
fastai 数据块 API
在任何应用中,将大量时间消耗在以适合于馈送到深度学习模型的格式来管理数据上。为了简化这一过程,以便任何 DL 实践者都可以专注于模型构建和解释,而不是数据管理,fastai 提出了 DataBlock API,它在数据管理方面非常出色。
通常,数据以下列两种方式之一进行组织
Imagenet 目录结构
图片由 Vinayak 提供
在这种格式中,数据是以文件夹方式管理的。训练集和验证集有单独的文件夹,并且它们中的每一个都有对应于各自类别的文件夹,这些类别具有对应于那些类别的相关数据。除此之外,树结构是针对一个以 Imagenet 目录形式管理的猫狗数据集的。
将信息包装在 csv 中
图片由 Vinayak 提供
在这种方法中,关于数据结构的信息被包装在一个 csv 中。它包含所有信息,如数据的路径、数据的类别、项目是否属于定型集或验证集等等。我们当前的数据集是以这种特殊格式管理的,我们将利用它来创建数据块。
fastai 的 datablock API 提供了对这两种结构甚至更多结构的支持,但是,我们将看看 API 的一般结构,以及我们如何使用它来解决这个问题。
datablock API 接受几个参数,有些是强制的,有些是可选的。我们将按顺序逐一讲解。
- **块:**为了指定输入和输出。这里,我们有一个图像作为输入,一个类别/标签作为输出。我们的输出是 CategoryBlock,但其他输出可以是 ImageBlock(用于自动编码器),MultiCategoryBlock(用于多标签分类)等。
- splitter: Jeremy 总是强调验证集的重要性,以便评估模型的性能,这是对的!如果不这样做,我们永远不会真正了解我们的模型表现得有多好。要做到这一点,我们可以指定一个 RandomSplitter 或者在我们的例子中指定一个条目是属于训练集还是验证集的列。
- get_x: 该参数要求输入的位置,即此处的图像块。在我们的数据帧中,第一列即 path 列包含路径,因此我们指定 cols = 0。我们也可以选择使用 pref 和 suff 参数在这里添加前缀和后缀。因为我们有图像的相对路径,要获得绝对路径,需要前缀。在 CSV 中,有时会删除路径列中项的扩展名,这正是后缀参数派上用场的地方。
- get_y: 该参数要求输出值。在 dataframe 中,由于第 4 列即 minifigure_name 是我们想要预测的标签,我们在 get_y 参数的 ColReader 对象中指定 cols = 3。
- item_tfms: 在为神经网络训练制作一批项目之前,我们需要应用一些变换来确保它们都是相同的大小(通常是正方形),并且在某些其他情况下,还需要一些其他变换。这些在这个论点中都有提及。
- batch_tfms: 这些是您希望用于通过裁剪、缩放、透视扭曲和其他此类变换使模型学习一般特征的增强方法。如果您已经有一个包含大量图像的大型数据集,您可以选择忽略此参数,否则,添加变换来学习一般化的模型而不是过度拟合的模型总是有帮助的。
一旦我们有了 DataBlock API 对象,我们就可以使用这个对象创建数据加载器,并将其输入到模型中进行训练。在创建 dataloader 之后,我们可以看到如何使用 show_batch 方法将数据输入到模型中,随后可以使用 vocab 属性来查看数据集中作为一个整体出现了多少个类/标签。
图片由 Vinayak 提供
dataloaders 对象包含训练和验证数据加载器。vocab 中的项目对应于与列车数据加载器相关的类别,验证数据加载器的标签/类别数量可能少于或等于列车数据加载器的标签/类别数量。另外,请注意,在 show_batch 方法中,您可以提供想要查看的项目数量,但是如果该数量大于批处理大小(9,而不是 bs 的 8),那么您将只能看到与批处理大小一样多的图像。
训练分类模型
一旦你有了一个数据加载器,下一步就是创建一个模型,并用一个合适的优化算法来训练它。fastai 已经抽象了很多这些东西,并为你提供了一个非常简单的学习对象,它也有很多参数,但让我强调下面最重要的几个。
图片由 Vinayak 提供
我们的学习者对象采用的强制参数如下:
- dls: 我们使用上面的数据块 API 定义的 dataloader 对象。它包含训练和验证数据集及其标签。
- **模型:**这是您想要使用的模型架构。因为我们正在进行迁移学习,所以我们将使用一个根据 ImageNet 权重训练的预定义 resnet101 模型。但是,如果您愿意,您可以通过继承 nn 来构建自己的 PyTorch 模型。模块类及其转发方法的实现;这超出了本文的范围,所以我们不在这里讨论。
- loss_func: 也称为目标/成本函数,这是优化算法试图最小化的函数(在大多数情况下;除非你定义了一个最大化的目标)。对于分类,交叉熵损失和回归 MSE 损失是最常用的损失函数。
其他可选但重要的参数是 opt_func 和 metrics,opt _ func 指定用于训练模型的优化算法,metrics 指定衡量性能的指标(可以是准确度、精确度、召回率、任何自定义指标)。还有一个调用不同回调的功能,这不在本文的讨论范围之内。你可以参考这里了解更多关于相同的东西。
一旦我们有了学习者对象,我们就可以利用 lr_find 函数为我们的模型找到一个最优的学习率。查看损失与学习率曲线,我们应该选择损失最小的学习率或略低于该点的学习率。对学习速率保持保守是有好处的,因为在我个人看来,延迟收敛比超过最佳点更容易容忍。
图片由 Vinayak 提供。
该函数还给出 lr_min 和观察到损耗下降最大的点的建议。lr_min 是对最小学习速率的估计,应该选择该最小学习速率,以便看到适当的训练速度,而不会非常担心跳过损失面中的最佳点,同时确保模型正在学习某些东西并且参数更新正在发生。因此,在这种情况下,让我们选择 0.01 的学习率并开始训练。
图片由 Vinayak 提供
由于我们只有大约 154 个训练图像,每个历元花费大约 4 秒进行验证和度量计算。在这种情况下,对于 resnet101 预训练模型,其顶部 fc 层和几个倒数第二卷积层获得权重更新,而网络的其余部分被冻结,即权重更新不会再向后传播。根据经验,这种微调方法在为定制任务采用预先训练的模型时是最好的;然而,经过实质性的改进后,例如当错误率下降到 10%或准确率达到近 90%时,我们也可以解冻网络的这一部分,并使用现在贯穿整个神经网络的参数更新来再次训练模型。
图片由 Vinayak 提供
这正是我们在这里所做的。在训练了 25 个时期后,我们解冻了模型,并在 lr_find 的帮助下检查了良好的学习率,并运行了 5 个时期的训练循环。然而,我们没有发现错误率有任何实质性的改善。从 10.27%下降到 8.9%;这表明模型现在已经饱和,无论您对模型做什么,除非您提供新的数据,否则不会对模型的准确性产生任何重大影响。
为了保存这个模型以便将来解释,您可以简单地使用命令
learn.export("filename.pkl")
这将把模型保存为一个名为 filename 的 pkl 文件,以后可以重新加载该文件进行推理。现在我们已经完成了所有的训练部分,让我们来解释这个模型,看看它已经做出的预测。
解释分类模型
在建立模型之后,需要测量模型的性能以确保其可用性,fastai 为此提供了一个类分类解释。我们可以用适合培训部分的学习者对象创建这个类的一个实例。
一旦我们做到了这一点,我们就可以观察验证数据的混淆矩阵,看看错误发生在哪里以及有多少个错误。
图片由 Vinayak 提供
这个整体结构看起来不错。在理想情况下,对角线完全饱和,所有其他非对角线元素为零。这里我们可以看到事实并非如此。这意味着我们的模型把一些动作人物分类错了,例如罗恩·韦斯莱被错误地归类为哈利·波特,一个 YODA 的人物被错误地归类为罗恩·韦斯莱,等等。为了特别突出那些被错误分类的,ClassificationInterpretation 类还多了一个方法。
图片由 Vinayak 提供
这里我们可以看到错误分类项目的元组。每个元组的结构分别为(基础事实、预测、误分类数)。可选地,您还可以提供一个参数,该参数只查看那些被错误分类超过某个阈值次数的对。这可以帮助我们确定需要更多关注的配对。因此,我们可以做出决定,如添加更多的数据或删除错误标记的数据等。
虽然在我的应用程序中,所有的东西都被整齐地标记了,但还是会有如下的错误标记。上面的代码有助于在笔记本中创建一个内嵌的 GUI,基本上可以用来保存/删除/移动项目。这存在于 fastai.vision 包的 widgets 类中。如果您有时不确定数据集中的标签,像这样审核数据集值得一试。
图片由 Vinayak 提供
这就是这篇文章的内容。我希望你了解开始使用 fastai 制作你自己的图像分类器的步骤。它在数据预处理、模型训练和模型解释方面为我节省了大量时间,特别是在深度学习方面。与 PyTorch 不同,在 py torch 中,我们必须定义数据集和数据加载器,datablock API 消除了对这一步骤的需要,因为它很好地将一切打包到一个函数调用中。希望你喜欢这篇文章,感谢你通读!
参考
数据湖之上的数据库—第 1 部分
第 1 部分(共 2 部分)—了解 Databricks Delta Lake 的基础知识—ACID 事务、检查点、事务日志和时间旅行
图片由皮克斯拜的 Gerd Altmann 提供
回到 8 年前,我仍然记得我采用 Hadoop 和 Spark 等大数据框架的日子。由于许多原因,来自数据库背景的这种适应具有挑战性。最大的挑战是大数据框架中缺少类似数据库的事务。为了弥补这个缺失的功能,我们必须开发几个例程来执行必要的检查和测量。然而,这一过程既繁琐又耗时,而且很容易出错。
另一个让我夜不能寐问题是可怕的变更数据捕获(CDC)。数据库有一种方便的方式来更新记录并向用户显示记录的最新状态。另一方面,在大数据中,我们接收数据并将其存储为文件。因此,每日增量摄取可能包含新插入、更新或删除的数据的组合。这意味着我们最终会在数据湖中多次存储同一行。这产生了两个问题:
- 重复数据—在某些情况下,同一行存在多次(更新和删除的数据)
- 数据分析—除非数据已经过重复数据消除,否则用户在看到同一行的多个实例时会感到困惑
那么,到目前为止,我们是如何处理这种情况的:
- 一天—接收完整数据集—完整表格
- 第 2 天-第 n 天—确保交付的增量数据(增量)带有记录更新时间戳和模式(插入/更新/删除)
- 在原始区域中接收数据后,运行 Hive/Mapreduce/Spark 修复作业,将增量数据与完整数据合并。
- 然而,在这个阶段,它巧妙地使用了移除重复项的功能,比如对主键分区的 RANK()和记录更新时间戳 DESC
- 过滤秩=1 的行会给出最近更新的行
- 用 Mode=Delete 删除行
- 将上述数据集保存到监管区——然后与用户社区共享这些数据,以便进一步分析
如你所见,上述过程非常复杂。需要一种更好的方法。
三角洲湖的救援
由 Databricks 开发的 Delta Lake 为批处理和流操作的数据湖带来了 ACID 事务支持。Delta Lake 是一个开源存储层,用于 HDFS、AWS S3、Azure 数据湖存储或谷歌云存储上的大数据工作负载。
Delta Lake 包含许多对数据工程师有用的酷功能。让我们在两部分系列中探索其中的一些特性:
第 1 部分:ACID 事务、检查点、事务日志和时间旅行
第二部分:真空,图式进化,历史
**用例:**一个电子商务网站销售来自多家供应商的产品。每个供应商每天都会发送其产品的最新价格。
产品 _aug20.csv
产品 _aug21.csv
该电子商务公司希望根据供应商每天发送的最新价格来调整其网站上的定价信息。此外,他们希望跟踪 ML 型号的价格。左边是每天收到的数据文件的示例。
让我们从下载数据开始:
$ git clone https://github.com/mkukreja1/blogs.git
假设今天是 8 月 20 日,您收到了文件— products_aug20.csv
将数据文件保存到 HDFS
$ hadoop fs -mkdir -p /delta_lake/raw
$ hadoop fs -put blogs/delta-lake/products_aug20.csv /delta_lake/raw
完整的笔记本可在**/delta _ lake/delta _ lake-demo-1 . ipynb 获得。**让我解释一下下面的每个步骤:
首先用 Delta Lake 包启动 Spark 会话,然后导入 Python APIs
from pyspark.sql import SparkSession
import pyspark
from pyspark.sql.functions import *
spark = pyspark.sql.SparkSession.builder.appName("Product_Price_Tracking") \
.config("spark.jars.packages", "io.delta:delta-core_2.12:0.7.0") \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") \
.getOrCreate()from delta.tables import *
使用最近收到的数据——products _ aug 20 . CSV——创建 Spark 数据框架
df_productsaug20 = spark.read.csv('hdfs:///delta_lake/raw/products_aug20.csv', header=True, inferSchema=True)
df_productsaug20.show()+---------+----------+-----+
|ProductID| Date|Price|
+---------+----------+-----+
| 200|2020-08-20| 20.5|
| 210|2020-08-20| 45.0|
| 220|2020-08-20|34.56|
| 230|2020-08-20|23.67|
| 240|2020-08-20|89.76|
+---------+----------+-----+
现在让我们将数据存储在三角洲湖中。Delta Lake 使用版本化的拼花文件将您的数据存储在您的云存储中。此外,还会存储一个事务日志来跟踪数据随时间的变化。
df_productsaug20.write.format("delta").option("path", "hdfs:///delta_lake/products").saveAsTable("products")
让我们看看日期在 HDFS 是如何存储的。记下存储一段时间内的更改的 _delta_log 目录。
每次提交= 1 个 JSON 文件,以 00000000000000000.json 开始
每 10 次提交,就会执行一个检查点,将以前的 JSON 文件合并成一个 parquet 文件。
$ hadoop fs -ls /delta_lake/products
Found 2 items
drwxr-xr-x - mkukreja supergroup 0 2020-08-26 20:43 /delta_lake/products/_delta_log
-rw-r--r-- 2 mkukreja supergroup 1027 2020-08-26 20:43 /delta_lake/products/part-00000-37f5ec8d-5e21-4a01-9f19-7e9942196ef6-c000.snappy.parquet$ hadoop fs -cat /delta_lake/products/_delta_log/00000000000000000000.json
2020-08-26 20:44:42,159 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
{"commitInfo":{"timestamp":1598489011963,"operation":"CREATE TABLE AS SELECT","operationParameters":{"isManaged":"false","description":null,"partitionBy":"[]","properties":"{}"},"isBlindAppend":true,"operationMetrics":{"numFiles":"1","numOutputBytes":"1027","numOutputRows":"5"}}}
{"protocol":{"minReaderVersion":1,"minWriterVersion":2}}
{"metaData":{"id":"7788c86b-ae7e-47be-ac43-76c1f3f0506f","format":{"provider":"parquet","options":{}},"schemaString":"{\"type\":\"struct\",\"fields\":[{\"name\":\"ProductID\",\"type\":\"integer\",\"nullable\":true,\"metadata\":{}},{\"name\":\"Date\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"Price\",\"type\":\"double\",\"nullable\":true,\"metadata\":{}}]}","partitionColumns":[],"configuration":{},"createdTime":1598489010883}}
{"add":{"path":"part-00000-37f5ec8d-5e21-4a01-9f19-7e9942196ef6-c000.snappy.parquet","partitionValues":{},"size":1027,"modificationTime":1598489011874,"dataChange":true}}$ hadoop fs -cat /delta_lake/products/_delta_log/00000000000000000000.json
2020-08-26 20:44:42,159 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
{"commitInfo":{"timestamp":1598489011963,"operation":"CREATE TABLE AS SELECT","operationParameters":{"isManaged":"false","description":null,"partitionBy":"[]","properties":"{}"},"isBlindAppend":true,"operationMetrics":{"numFiles":"1","numOutputBytes":"1027","numOutputRows":"5"}}}
{"protocol":{"minReaderVersion":1,"minWriterVersion":2}}
{"metaData":{"id":"7788c86b-ae7e-47be-ac43-76c1f3f0506f","format":{"provider":"parquet","options":{}},"schemaString":"{\"type\":\"struct\",\"fields\":[{\"name\":\"ProductID\",\"type\":\"integer\",\"nullable\":true,\"metadata\":{}},{\"name\":\"Date\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"Price\",\"type\":\"double\",\"nullable\":true,\"metadata\":{}}]}","partitionColumns":[],"configuration":{},"createdTime":1598489010883}}
{"add":{"path":"part-00000-37f5ec8d-5e21-4a01-9f19-7e9942196ef6-c000.snappy.parquet","partitionValues":{},"size":1027,"modificationTime":1598489011874,"dataChange":true}}
这就是我们如何使用 Spark SQL 查询 Delta Lake 中最近保存的数据
spark.sql('SELECT * FROM products').show()+---------+----------+-----+
|ProductID| Date|Price|
+---------+----------+-----+
| 200|2020-08-20| 20.5|
| 210|2020-08-20| 45.0|
| 220|2020-08-20|34.56|
| 230|2020-08-20|23.67|
| 240|2020-08-20|89.76|
+---------+----------+-----+
您可以使用时间旅行来查询增量表的以前快照。如果想在数据被覆盖之前访问它,可以使用versionAsOf
选项查询表的快照。
deltaTable.update("ProductID = '200'", { "Price": "'48.00'" } )df = spark.read.format("delta").option(**"versionAsOf", 1**).load("hdfs:///delta_lake/products")
df.show()*# Notice the value of Price for ProductID=200 has changed in version 1 of the table*+---------+----------+-----+
|ProductID| Date|Price|
+---------+----------+-----+
| 200|2020-08-20| **48.0**|
| 210|2020-08-20| 45.0|
| 220|2020-08-20|34.56|
| 230|2020-08-20|23.67|
| 240|2020-08-20|89.76|
+---------+----------+-----+df = spark.read.format("delta").option(**"versionAsOf", 0**).load("hdfs:///delta_lake/products")
df.show()*# Notice the value of Price for ProductID=200 is the older snapshot in version 0*+---------+----------+-----+
|ProductID| Date|Price|
+---------+----------+-----+
| 200|2020-08-20| **20.5**|
| 210|2020-08-20| 45.0|
| 220|2020-08-20|34.56|
| 230|2020-08-20|23.67|
| 240|2020-08-20|89.76|
+---------+----------+-----+
让我们执行另一个 DML 操作,这次删除 ProductID=210。
deltaTable.delete("ProductID = 210")
df = spark.read.format("delta").option(**"versionAsOf", 2**).load("hdfs:///delta_lake/products")
df.show()*# Notice the value of Price for ProductID=210 is missing in Version 2*+---------+----------+-----+
|ProductID| Date|Price|
+---------+----------+-----+
| 200|2020-08-20| 48.0|
| 220|2020-08-20|34.56|
| 230|2020-08-20|23.67|
| 240|2020-08-20|89.76|
+---------+----------+-----+
请注意,事务日志有所进展,每个事务一个日志
$ hadoop fs -ls /delta_lake/products/_delta_log
Found 3 items
-rw-r--r-- 2 mkukreja supergroup 912 2020-08-21 13:14 /delta_lake/products/_delta_log/00000000000000000000.json
-rw-r--r-- 2 mkukreja supergroup 579 2020-08-24 11:03 /delta_lake/products/_delta_log/00000000000000000001.json
-rw-r--r-- 2 mkukreja supergroup 592 2020-08-24 11:14 /delta_lake/products/_delta_log/00000000000000000002.json
特别注意事务日志的 JSON 中的操作属性
$ hadoop fs -cat /delta_lake/products/_delta_log/*.json{"commitInfo":{"timestamp":1598489978902,**"operation":"CREATE TABLE AS SELECT"**,"operationParameters":{"isManaged":"false","description":null,"partitionBy":"[]","properties":"{}"},"isBlindAppend":true,"operationMetrics":{"numFiles":"1","numOutputBytes":"1027","numOutputRows":"5"}}}
{"protocol":{"minReaderVersion":1,"minWriterVersion":2}}
{"metaData":{"id":"47d211fc-7148-4c85-aa80-7d9aa8f0b7a2","format":{"provider":"parquet","options":{}},"schemaString":"{\"type\":\"struct\",\"fields\":[{\"name\":\"ProductID\",\"type\":\"integer\",\"nullable\":true,\"metadata\":{}},{\"name\":\"Date\",\"type\":\"string\",\"nullable\":true,\"metadata\":{}},{\"name\":\"Price\",\"type\":\"double\",\"nullable\":true,\"metadata\":{}}]}","partitionColumns":[],"configuration":{},"createdTime":1598489977907}}
{"add":{"path":"part-00000-8c43a47a-02bf-4bc2-a3be-aaabe9c409bd-c000.snappy.parquet","partitionValues":{},"size":1027,"modificationTime":1598489978816,"dataChange":true}}
2020-08-26 21:07:41,120 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
{"commitInfo":{"timestamp":1598490235896,**"operation":"UPDATE"**,"operationParameters":{"predicate":"(ProductID#609 = 200)"},"readVersion":0,"isBlindAppend":false,"operationMetrics":{"numRemovedFiles":"1","numAddedFiles":"1","numUpdatedRows":"1","numCopiedRows":"4"}}}
{"remove":{"path":"part-00000-8c43a47a-02bf-4bc2-a3be-aaabe9c409bd-c000.snappy.parquet","deletionTimestamp":1598490235237,"dataChange":true}}
{"add":{"path":"part-00000-272c0f65-433e-4901-83fd-70b78667ede0-c000.snappy.parquet","partitionValues":{},"size":1025,"modificationTime":1598490235886,"dataChange":true}}
2020-08-26 21:07:41,123 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
{"commitInfo":{"timestamp":1598490393953,**"operation":"DELETE"**,"operationParameters":{"predicate":"[\"(`ProductID` = 210)\"]"},"readVersion":1,"isBlindAppend":false,"operationMetrics":{"numRemovedFiles":"1","numDeletedRows":"1","numAddedFiles":"1","numCopiedRows":"4"}}}
{"remove":{"path":"part-00000-272c0f65-433e-4901-83fd-70b78667ede0-c000.snappy.parquet","deletionTimestamp":1598490393950,"dataChange":true}}
{"add":{"path":"part-00000-73a381e1-fa68-4323-81b9-c42dea484542-c000.snappy.parquet","partitionValues":{},"size":1015,"modificationTime":1598490393946,"dataChange":true}}
现在是第二天,你收到了一个新的数据文件。现在让我们将第二天的新数据集(products_aug21.csv)合并到 Delta Lake 中
$ hadoop fs -put csv/products_aug21.csv /delta_lake/raw
$ hadoop fs -ls /delta_lake/raw
Found 2 items
-rw-r--r-- 2 mkukreja supergroup 132 2020-08-21 13:00 /delta_lake/raw/products_aug20.csv
-rw-r--r-- 2 mkukreja supergroup 220 2020-08-24 11:33 /delta_lake/raw/products_aug21.csv
执行向上插入操作。这意味着,如果新文件(products_aug21.csv)中的数据与 Delta Lake 中的任何现有数据匹配(基于 ProductID 上的连接条件),则更新价格,否则插入新行。
df_productsaug21 = spark.read.csv('hdfs:///delta_lake/raw/products_aug21.csv', header=True, inferSchema=True)
df_productsaug21.show()deltaTable.alias("products").merge(
df_productsaug21.alias("products_new"),
"products.ProductID = products_new.ProductID") \
.**whenMatchedUpdate**(set = { "Price" : "products_new.Price" } ) \
.**whenNotMatchedInsert**(values =
{
"ProductID": "products_new.ProductID",
"Date": "products_new.Date",
"Price": "products_new.Price"
}
).execute()
更新后检查表格的最新版本。您可能注意到 ProductID=240 经历了 whenMatchedUpdate 操作,而 ProductID=240 直到 280 经历了 whenNotMatchedInsert 操作。
spark.table("products").show()+---------+----------+-----+
|ProductID| Date|Price|
+---------+----------+-----+
| 230|2020-08-20|23.67|
| 210|2020-08-21| 46.0|
| 250|2020-08-21|89.76|
| 220|2020-08-20|34.56|
| 240|2020-08-20|90.82|
| 200|2020-08-20| 25.5|
| 260|2020-08-21|54.55|
| 280|2020-08-21|44.78|
| 270|2020-08-21|96.32|
+---------+----------+-----+
对于每 10 次提交,Delta Lake 都会在_delta_log
子目录中以 Parquet 格式保存一个检查点文件。因为检查点文件是 Parquet 格式的,所以与低效的 JSON 文件相比,它允许 Spark 执行更快的读取。
让我们通过更新几行来看看这是如何发生的:
deltaTable.update("ProductID = '230'", { "Price": "'33.67'" } )
deltaTable.update("ProductID = '210'", { "Price": "'56.00'" } )
deltaTable.update("ProductID = '250'", { "Price": "'99.76'" } )
deltaTable.update("ProductID = '220'", { "Price": "'44.56'" } )
deltaTable.update("ProductID = '240'", { "Price": "'100.82'" } )
deltaTable.update("ProductID = '200'", { "Price": "'35.5'" } )
deltaTable.update("ProductID = '260'", { "Price": "'64.55'" } )
deltaTable.update("ProductID = '280'", { "Price": "'54.78'" } )
deltaTable.update("ProductID = '270'", { "Price": "'106.32'" } )
检查_delta_log
子目录。在 10 次提交之后,创建了 0000000000000010 . check point . parquet 文件。检查点文件以 Parquet 格式保存表在某个时间点的状态,这样就可以非常高效地检索历史。
$ hadoop fs -ls /delta_lake/products/_delta_log
Found 15 items
-rw-r--r-- 2 mkukreja supergroup 912 2020-08-21 13:14 /delta_lake/products/_delta_log/00000000000000000000.json
-rw-r--r-- 2 mkukreja supergroup 579 2020-08-24 11:03 /delta_lake/products/_delta_log/00000000000000000001.json
-rw-r--r-- 2 mkukreja supergroup 592 2020-08-24 11:14 /delta_lake/products/_delta_log/00000000000000000002.json
-rw-r--r-- 2 mkukreja supergroup 2255 2020-08-24 11:39 /delta_lake/products/_delta_log/00000000000000000003.json
-rw-r--r-- 2 mkukreja supergroup 578 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000004.json
-rw-r--r-- 2 mkukreja supergroup 578 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000005.json
-rw-r--r-- 2 mkukreja supergroup 578 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000006.json
-rw-r--r-- 2 mkukreja supergroup 578 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000007.json
-rw-r--r-- 2 mkukreja supergroup 578 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000008.json
-rw-r--r-- 2 mkukreja supergroup 578 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000009.json
**-rw-r--r-- 2 mkukreja supergroup 14756 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000010.checkpoint.parquet**
-rw-r--r-- 2 mkukreja supergroup 578 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000010.json
-rw-r--r-- 2 mkukreja supergroup 579 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000011.json
-rw-r--r-- 2 mkukreja supergroup 579 2020-08-24 12:05 /delta_lake/products/_delta_log/00000000000000000012.json
-rw-r--r-- 2 mkukreja supergroup 25 2020-08-24 12:05 /delta_lake/products/_delta_log/_last_checkpoint
很多好东西。我在数据工程和数据科学领域已经玩了几年了,我可以有把握地告诉你,这些特性是一种生活品味。无需再为存储和显示数据库中的最新变更数据集而费尽周折。
在下一部分中,我们将深入探讨 Delta Lake 的一些高级主题,包括分区、模式演化、数据血统和真空。
我希望这篇文章是有帮助的。三角洲湖作为大数据 Hadoop、Spark & Kafka 课程的一部分,由 Datafence 云学院提供。课程是周末自己在网上教的。