PySpark简介 - 第2部分- 选择、过滤和排序数据

509 阅读6分钟

介绍PySpark第二部分 - 选择、过滤和排序数据

这是一系列博文的第二部分,是对PySpark的介绍。

本系列博文的其他部分可以在这里找到。

在这一部分中,我将涵盖。

  • 选择列
  • 筛选行
    • 连锁条件
    • 字符串匹配
    • 针对列表的匹配
    • 对空值进行过滤
    • 丢弃重复的数据
  • 数据排序

选择列

select 我们可以使用DataFrame 的方法来选择我们感兴趣的列。

如果我们加载我们在上一节中看到的pokemon parquet文件,那么我们就可以只选择我们感兴趣的列,由于命令是被懒惰地评估的,当我们从parquet文件中加载时,我们最终只会加载我们感兴趣的列。

pokemon = spark.read.parquet('/mnt/tmp/pokemon.parquet')
pokemon = pokemon.select('#', 'Name', 'Type1', 'Type2', 'Generation')
display(pokemon.limit(10))

.table-result-container { max-height: 300px; overflow: auto; } table, th, td { border:1px solid black; border-collapse: collapse; } th, td { padding:5px; } th { text-align: left; }

#名称类型1类型2代数
1布巴索尔草系毒药1
2伊维萨乌草类蛇毒1
3维努萨龙草质毒药1
3维努沙尔巨型维努沙尔草质毒药1
4魅魔火焰1
5恶魔之眼(Charmeleon火灾1
6蜥蜴火焰飞翔1
6魔法师Mega Charizard X火焰1
6火蜥蜴Mega Charizard Y火龙飞翔1
7小松鼠水系1

我们还可以使用DataFrame的colRegex 方法来匹配列,这将给我们提供匹配正则表达式的列,让我们试试。

display(
    pokemon.select(
        pokemon.colRegex('`^T[a-z]*[1-9]$`')
    ).limit(5)
)
类型1类型2
草类毒药
草类毒药
草类毒草
毒草
火灾

过滤行

我们可以用类似于在pandas中的方式来过滤行,比如说我们只想要第二代小精灵。

second_gen_pokemon = pokemon[pokemon['Generation'] == 2]
display(second_gen_pokemon.limit(10))
#名称类型1类型2代号
152奇科里塔2
153贝利夫草地2
154牧羊犬草地2
155骏达奎尔2
156奎拉瓦火灾2
157大爆炸火灾2
158托托迪尔2
159鳄鱼人2
160法拉里加特饮用水2
161森特雷特正常2

连锁条件

我们可以使用&| 来链接条件,所以如果我们想选择所有"Ground" 类型的小精灵。

ground_type_pokemon =  pokemon[
    (pokemon['Type1'] == 'Ground')
    | (pokemon['Type2'] == 'Ground')
]
display(ground_type_pokemon.limit(5))
#名称类型1类型2代号
27沙虫地面1
28泥石流(Sandslash地面1
31尼多奎恩毒药地面1
34尼多金毒药地面1
50挖掘机地面1

字符串匹配

我们可以使用startswith,endswith, 或contains 来过滤字符串。

display(pokemon[pokemon['Name'].startswith('Nido')])

.table-result-container { max-height: 300px; overflow: auto; } table, th, td { border:1px solid black; border-collapse: collapse; } th, td { padding:5px; } th { text-align: left; }

#名称类型1类型2代号
29尼多兰♀毒药1
30尼多里纳麻醉剂1
31尼多奎恩药品地面1
32尼多兰♂毒药1
33尼多里诺麻醉剂1
34尼多金毒药地面1

我们还可以使用likerlike ,其中rlike 用于在正则表达式上进行匹配 - 让我们寻找名字以 "R "开头、以 "n "结尾的小精灵。

display(
    pokemon[        pokemon['Name'].rlike('^[Rr].+n$')
    ]
)
#名称类型1类型2代号
111雷恩地面岩石1
112雷德恩地面岩石1

针对列表进行匹配

我们可以根据一个列表中的值进行过滤,使用isin

display(
    pokemon[        pokemon['#'].isin([121, 131, 141, 151])
    ]
)
#名称类型1类型2代号
121斯塔米水系通灵1
131拉普拉斯水系1
141卡布托普斯岩石1
151苗族通灵1

NOT (~)

我们可以通过使用a tilde~ 符号来获得上述任何过滤器的反面。

display(
    pokemon[        ~(pokemon['Type1'].isin(['Grass', 'Fire', 'Water', 'Bug']))
        & ~(pokemon['Generation'] == 1)
    ].limit(10)
)
#名称类型1类型2代号
161哨兵正常2
162芙蕾特正常2
163虎头蛇尾正常飞翔2
164野鸟普通飞行2
169鹦鹉毒药鸓 オヤエオ2
172皮库电击2
173克利法仙女2
174伊格利布夫正常仙女2
175托格皮仙女2
176托吉迪仙女飞翔2

对空值进行过滤

我们可以使用isNull ,对空值进行过滤,所以如果我们只想寻找具有单一类型的小精灵,我们可以这样做。

single_type_pokemon = pokemon[pokemon['Type2'].isNull()]
display(single_type_pokemon.limit(5))
#名称类型1类型2代号
4魅力鸟1
5恶魔之眼(Charmeleon火灾1
7小松鼠水系1
8瓦尔特尔1
9布拉斯托斯1

或者反过来说,如果我们只想要有Type1和Type2的小精灵,我们就用我们的"~"。

dual_type_pokemon = pokemon[~pokemon['Type2'].isNull()]
display(dual_type_pokemon.limit(5))
#名称类型1类型2代数
1布巴索尔草系毒药1
2伊维萨乌草类蛇毒1
3维努萨龙草质毒药1
3维努沙尔巨型维努沙尔毒药1
6蜥蜴火焰飞行1

丢掉重复的行

你可能已经注意到,有时我们有小精灵的编号(#)重复,因为我们有该小精灵的普通版本和 "巨型 "版本,我们可以使用DataFrame的dropDuplicates 方法删除重复的数字。如果我们想只删除任何重复的行,我们不需要提供一个列的子集,但通过提供一个列的子集,我们可以删除在任何单一/组合的列中有重复的行。

display(pokemon.dropDuplicates(subset=['#']).limit(10))
#名称类型1类型2代数
1布巴索尔草系毒药1
2伊维萨乌草类蛇毒1
3维努萨龙草质毒药1
4魅魔火焰1
5恶魔之眼(Charmeleon火灾1
6蜥蜴火焰飞翔1
7小松鼠水系1
8瓦尔特尔1
9布拉斯托斯1
10卡特彼勒虫子1

注意,现在我们的数据中不再有MegaVenusaur或MegaCharizard。

数据排序

目前我们的DataFrame是按小精灵的编号排序的 (#),如果我们再次加载数据,我们可以选择用sortorderBy 来按其他属性排序。

pokemon = spark.read.parquet('/mnt/tmp/pokemon.parquet')
pokemon = pokemon.sort('HP', ascending=False)
display(pokemon.limit(10))
#名称类型1类型2HP攻击力防御攻击力防御速度寿命传奇的
242布莱西普通255101075135.0552假的
113昌西正常2505535105.0501假的
202沃布费特精神病学19033583358.0332假的
321纬度17090459045.0603假的
594阿罗莫拉16575804045.0655假的
143斯诺拉正常1601106565110.0301假的
289荡气回肠正常1501601009565.01003假的
426漂浮物幽灵鸓 オヤエオヤエオヤエオヤエオヤエオヤエ15080449054.0804假的
487吉拉蒂纳改变的形象幽灵150100120100120.0904
487吉拉蒂纳原产地名称幽灵150120100120100.0904

有多个小精灵的HP为150,如果我们想先按"HP" ,后按"Attack" ,但按攻击力升序排列,我们可以这样做。

pokemon = pokemon.sort(['HP', 'Attack'], ascending=[0, 1])
display(pokemon.limit(10))

.table-result-container { max-height: 300px; overflow: auto; } table, th, td { border:1px solid black; border-collapse: collapse; } th, td { padding:5px; } th { text-align: left; }

#名称类型1类型2HP攻击力防御攻击力防御速度寿命传奇的
242布莱西普通255101075135.0552假的
113昌西正常2505535105.0501假的
202沃布费特精神病学19033583358.0332假的
321纬度17090459045.0603假的
594阿罗莫拉16575804045.0655假的
143斯诺拉正常1601106565110.0301假的
426漂浮物幽灵鸓 オヤエオヤエオヤエオヤエオヤエオヤエ15080449054.0804假的
487吉拉蒂纳改变的形象幽灵150100120100120.0904
487吉拉蒂纳原产地名称幽灵150120100120100.0904
289荡气回肠正常1501601009565.01003错误