前言: DataFrame需要重点关注的是如何取使用,利用DataFrame来解决实际业务中的数据问题。熟练掌握DataFrame的各种api的使用就像相当于手握一把非常重要且高效的利器,实际数据工程可以大量的被用到。 本文是对DataFrame概念和过去实际工作中用到过的DataFrame中关于数据查看的一个回忆性总结。
目录
.distinct() 行去重和.dropDuplicates按指定列去重
.head(num) 以及.take(num) 获取前num行记录
.unionByName 两个DataFrame根据列名进行合并。
withColumn中,df.column.cast('type')数据类型转换
样例数据,简单建一个DataFrame
sc = spark.sparkContext
# 创建一个SparkDataFrame
rdd = sc.parallelize([("Sam", 28, 88, "M"),
("Flora", 28, 90, "F"),
("Run", 1, 60, None),
("Peter", 55, 100, "M"),
("Mei", 54, 95, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"]) # 创建DataFrame的一种方式,用rdd.toDF 来建
DataFrame.show( num) 以表格的形式显示头num行,函数返回值为NoneType 。
tmp = test_exp_data.show(5)
print(type(tmp)) # 返回结果为 <class 'NoneType'>.
输出: +-----+---+-----+----+ | name|age|score| sex| +-----+---+-----+----+ | Sam| 28| 88| M| |Flora| 28| 90| F| | Run| 1| 60|null| |Peter| 55| 100| M| | Mei| 54| 95| F| +-----+---+-----+----+ <class 'NoneType'>
以树的形式显示表中各个列的数据结构 ,返回类型为None
print(test_exp_data.printSchema())
输出:
root |-- name: string (nullable = true) |-- age: long (nullable = true) |-- score: long (nullable = true) |-- sex: string (nullable = true)
也可以直接输出,不用括号,也不会报错如
print(test_exp_data.printSchema)
返回一个int类型结果值
print(test_exp_data.count())
tmp = test_exp_data.count()
print(type(tmp)) # <class 'int'>
输出:
5 <class 'int'>
.distinct() 去掉重复的行,只保留第一次出现的行,得到不同的行,返回类型为DataFrame
### 去重
rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
("Flora", 28, 90.55, "F"),
("Flora", 28, 90.55, "F"),
("Flora", 45, 99.5, "F"),
("Mey", 1, None, "M"),
("Chery", 7, 80.23, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
#test_exp_data.show()
### .distinct()对数据集去重,去掉重复的行
test_exp_data.distinct().show()
结果:
+-----+---+-----+---+ | name|age|score|sex| +-----+---+-----+---+ | Sam| 28|88.52| M| |Flora| 28|90.55| F| |Flora| 45| 99.5| F| | Mey| 1| null| M| |Chery| 7|80.23| F| +-----+---+-----+---+
.dropDuplicates 按指定列去重,#对于改列的不同值,只保留在第一次出现的行
test_exp_data.dropDuplicates(['sex']).show()
结果:
+-----+---+-----+---+ | name|age|score|sex| +-----+---+-----+---+ |Flora| 28|90.55| F| | Sam| 28|88.52| M| +-----+---+-----+---+
limit方法获取指定DataFrame的前n行记录,得到一个新的DataFrame对象。
tmp = test_exp_data.limit(4)
print(type(tmp)) # DataFrame
tmp.show(2)
输出
<class 'pyspark.sql.dataframe.DataFrame'> +-----+---+-----+---+ | name|age|score|sex| +-----+---+-----+---+ | Sam| 28| 88| M| |Flora| 28| 90| F| +-----+---+-----+---+
不同于前面的show方法,这里的collect方法会将DF中的所有数据都获取到,并返回一个list。
print(test_exp_data.collect())
tmp= test_exp_data.collect()
print(type(tmp))
输出:
[Row(name='Sam', age=28, score=88, sex='M'), Row(name='Flora', age=28, score=90, sex='F'), Row(name='Run', age=1, score=60, sex=None), Row(name='Peter', age=55, score=100, sex='M'), Row(name='Mei', age=54, score=95, sex='F')] <class 'list'>
两个函数功能都是获取前num行记录汇总到一个list中。list中的每个元素都是一个row结构。
tmp = test_exp_data.head(3)
print(tmp)
print(type(tmp)) ## list
print(type(tmp[0]))
tmp = test_exp_data.take(3)
print(tmp)
print(type(tmp)) # <class 'list'>
print(type(tmp[0]))
输出:
[Row(name='Sam', age=28, score=88, sex='M'), Row(name='Flora', age=28, score=90, sex='F'), Row(name='Run', age=1, score=60, sex=None)] <class 'list'> <class 'pyspark.sql.types.Row'>
另一个输出完全一模一样。
df.sample(fraction=float_num) ,按fraction比例对行进行随机采样
print(test_exp_data.count())
samp = test_exp_data.sample(fraction=0.5)
print(samp.count())
输出:
5 3
选择的列数据构成一个新的dataframe返回。 可以有如下三种表示方法来选 。且都可以进行数据运算。
test_exp_data.select("name").show(1)
test_exp_data.select(test_exp_data.name).show(1)
test_exp_data.select(test_exp_data['name']).show(1)
都是输出:
+----+ |name| +----+ | Sam| +----+
选择多列的表示方式。注意第一种如果是单独只有列名时需要用list拼起来
test_exp_data.select(["name",'score']).show(1) # 选择多个列,可以是由string类型列名组成的list。注意要用list表示
test_exp_data.select(test_exp_data.name,test_exp_data.score).show(1) #也可以是df中逐个带着列名
test_exp_data.select(test_exp_data["name"],test_exp_data["score"]).show(1) #也可以是df中逐个带着列名
都是输出
+----+-----+ |name|score| +----+-----+ | Sam| 88| +----+-----+
另外,可以基于某列直接进行数据运算(数据类型要为非string)
test_exp_data.select(test_exp_data["name"],test_exp_data["score"]+1).show(1) # df中逐个带着列的数据还可以进行运算操作
test_exp_data.select(test_exp_data.name,test_exp_data.score+1).show(1)
selectExpr() 也可以选择数据并进行更加复杂的数据处理,直接选择的语句中就处理了。selectExpr方法本质与select方法中使用expr函数是一样的,可以直接对指定字段调用UDF函数,或者指定别名等。传入String类型参数,得到DataFrame对象。
如下实例:里面用as 重命名、用round四舍五入并指定保留小数位;
# 创建一个SparkDataFrame
rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
("Flora", 28, 90.55, "F"),
("Run", 1, 60, None),
("Peter", 55, 100, "M"),
("Mei", 54, 95, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
test_exp_data.selectExpr('name as new_name','round(score)','round(score,1)').show(3) # 第一个处理是起新命名,第二个是直接调用round函数进行四舍五入处理默认不保留小数位,第三个是保留一位小数
输出:
+--------+---------------+---------------+ |new_name|round(score, 0)|round(score, 1)| +--------+---------------+---------------+ | Sam| 89.0| 88.5| | Flora| 91.0| 90.5| | Run| null| null| +--------+---------------+---------------+
rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
("Flora", 28, 90.55, "F"),
("Chery", 7, 80.23, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
test_exp_data.show()#df1
+-----+---+-----+---+ | name|age|score|sex| +-----+---+-----+---+ | Sam| 28|88.52| M| |Flora| 28|90.55| F| |Chery| 7|80.23| F| +-----+---+-----+---+
rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
("Flora", 28, 90.55, "F"),
("Chery", 7, 80.23, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
test_exp_data.show()# df2
+---+------+-----+---+ |age| name|score|sex| +---+------+-----+---+ | 7|Chery2|80.23| F| | 28| Sam2|88.52| M| +---+------+-----+---+
## 两个df 根据列名进行合并
merge = test_exp_data.unionByName(test2).show()
结果:
+------+---+-----+---+ | name|age|score|sex| +------+---+-----+---+ | Sam| 28|88.52| M| | Flora| 28|90.55| F| | Chery| 7|80.23| F| |Chery2| 7|80.23| F| | Sam2| 28|88.52| M| +------+---+-----+---+
返回关于列的统计分布(个数统计count、数值均值mean、标准差stddev、最小值min、最大值max),结果展现形式为dataframe类型,可以用show查看。注意字符串类型的列并不会报错!且Min 和max会按照字典序进行排序 。
对于pyspark的dataframe的describe函数并不能统计出对应的分位数,如果想统计对应的百分位数,可以转换为pandas的dataframe后再通过参数percentiles去统计。
rdd = sc.parallelize([("Sam", 28, 88.52, "M"),
("Flora", 28, 90.55, "F"),
("Mey", 1, None, "M"),
("Chery", 7, 80.23, "F")])
test_exp_data = rdd.toDF(["name", "age", "score", "sex"])
test_exp_data.describe().show()
输出:
+-------+-----+------------------+-----------------+----+ |summary| name| age| score| sex| +-------+-----+------------------+-----------------+----+ | count| 4| 4| 3| 4| | mean| null| 16.0|86.43333333333334|null| | stddev| null|14.071247279470288|5.467287566365362|null| | min|Chery| 1| 80.23| F| | max| Sam| 28| 90.55| M| +-------+-----+------------------+-----------------+----+
也可以选择某列单独进行统计
test_exp_data.select('score').describe().show()
想统计百分位数,.toPandas().describe(percentiles=[....])
test_exp_data.toPandas().describe(percentiles=[0.0,0.01,0.2,0.5,0.90,1.0])
age score count 4.000000 3.000000 mean 16.000000 86.433333 std 14.071247 5.467288 min 1.000000 80.230000 0% 1.000000 80.230000 1% 1.180000 80.395800 20% 4.600000 83.546000 50% 17.500000 88.520000 90% 28.000000 90.144000 100% 28.000000 90.550000 max 28.000000 90.550000
关于百分位数的概念:第p百分位数(p%分位数)值满足:有p%的观察值小于或等于该值,至少有(100-p)%的观察值大于或等于该值。注意0%分位数是这组值中的最小值,100%分位数是这组值中的最大值。
分位数的概念如

功能类似describe,多了25%,50%,75%分位数,结果返回仍然是一个dataframe
test_exp_data.summary().show()
结果显示:
+-------+------------------+-----------------+ |summary| age| score| +-------+------------------+-----------------+ | count| 4| 3| | mean| 16.0|86.43333333333334| | stddev|14.071247279470288|5.467287566365362| | min| 1| 80.23| | 25%| 1| 80.23| | 50%| 7| 88.52| | 75%| 28| 90.55| | max| 28| 90.55| +-------+------------------+-----------------+
如: flash_res = flash_res.withColumn("label_float",flash_res.label.cast('float'))
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时
Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"
我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption
我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],