datafrane進階
- 1. 分組統計
- 2. join 操作
- 3. 缺失值處理
- 4. 空值判斷
- 5. 缺失值處理
- 6. 離羣點
- 7. 重複值
- 8. 生成新列
- 9. 類eval操作
- 10. 行的最大最小值
- 11. when操作
- 12. lag,lead平移
1. 分組統計
分組統計應該是用的最多的方法了,比如分地區求平均值,最大最小值等。
# 分組計算1
color_df.groupBy('length').count().show()
# 分組計算2:應用多函數
import pyspark.sql.functions as func
color_df.groupBy("color").agg(func.max("length"), func.sum("length")).show()
2. join 操作
# 1.生成測試數據
employees = [(1, "John", 25), (2, "Ray", 35), (3,"Mike", 24), (4, "Jane", 28), (5, "Kevin", 26),
(6, "Vincent", 35), (7,"James", 38), (8, "Shane", 32), (9, "Larry", 29), (10, "Kimberly", 29),
(11, "Alex", 28), (12, "Garry", 25), (13, "Max",31)]
employees=spark.createDataFrame(employees, schema=["emp_id","name","age"])
employees.show()
salary=[(1,1000),(2,2000),(3,3000),(4,4000)]
salary=spark.createDataFrame(salary, schema=["emp_id","salary"])
salary.show()
department=[(1,1000),(2,2000),(3,3000),(4,4000)]
department=spark.createDataFrame(department, schema=["emp_id","departement"])
department.show()
# 2.連接
# join默認是內連接,最終結果會存在重複列名
# 如果是pandas,重複列會用_x,_y等後綴標識出來,但spark不會
# join會在最後的dataframe中存在重複列
final_data = employees.join(salary, employees.emp_id == salary.emp_id, how='left')\
.join(department, employees.emp_id==department.emp_id)
final_data.show()
# 3.如果兩邊的關聯字段名相同,也可以省去很多麻煩
final_data = employees.join(salary, on='emp_id', how='left')\
.join(department, on='emp_id', how='left')
final_data.show()
# 4.多字段關聯
final_data = employees.join(salary, on=['emp_id','emp_name'], how='left')
# 5.外連接
# full outer join全外連接
df.join(df2, "name", "outer").select("id", "name", "age", "height").orderBy("id").show()
3. 缺失值處理
在join操作中,我們得到一個有缺失值的dataframe,接下來將對這個帶有缺失值的dataframe進行操作
# 1.刪除有缺失值的行
clean_data=final_data.na.drop()
clean_data.show()
# 2.用均值替換缺失值
import math
from pyspark.sql import functions as func # 導入spark內置函數
# 計算缺失值,collect()函數將數據返回到driver端,爲Row對象,[0]可以獲取Row的值
mean_salary = final_data.select(func.mean('salary')).collect()[0][0]
clean_data = final_data.na.fill({'salary':mean_salary})
# 3.如果一行至少2個缺失值才刪除該行
final_data.na.drop(thresh=2).show()
# 4.填充缺失值
# 對所有列用同一個值填充缺失值
df1.na.fill('unknown').show()
# 5.不同的列用不同的值填充
df1.na.fill({'LastName':'--', 'Dob':'unknown'}).show()
4. 空值判斷
有兩種空值判斷,一種是數值類型是nan,另一種是普通的None
# 類似 pandas.isnull
from pyspark.sql.functions import isnull, isnan
# 1.None 的空值判斷
df = spark.createDataFrame([(1, None), (None, 2)], ("a", "b"))
df.select(isnull("a").alias("r1"), isnull(df.a).alias("r2")).show()
# 2.nan的空值判斷
df = spark.createDataFrame([(1.0, float('nan')), (float('nan'), 2.0)], ("a", "b"))
df.select(isnan("a").alias("r1"), isnan(df.a).alias("r2")).show()
5. 缺失值處理
如果col1爲空則用col2填補,否則返回col1。
類似 pandas 的 where 或者 combine_first 方法
# pandas
#where即if-else函數
np.where(isnull(a),b,a)
# combine_first方法
#如果a中值爲空,就用b中的值填補
a[:-2].combine_first(b[2:])
#combine_first函數即對數據打補丁,用df2的數據填充df1中的缺失值
df1.combine_first(df2)
# pyspark
df = spark.createDataFrame([(1.0, float('nan')), (float('nan'), 2.0)], ("a", "b"))
df.select(nanvl("a", "b").alias("r1"), nanvl(df.a, df.b).alias("r2")).show()
6. 離羣點
# 需要提醒的是,列的計算都是放在select裏面的
# 1.先計算均值
mean_salary = final_data.select(func.mean('salary')).collect()[0][0]
# 2.再計算方差
devs=final_data.select(((final_data.salary-mean_salary)**2).alias('deviation'))
# 3.再計算標準差
stddev = math.floor(math.sqrt(devs.groupBy().avg('deviation').first()[0]))
# 4.用均值的兩倍標準差替代離羣值
no_outlier = final_data.select(
final_data.emp_id, final_data.name, final_data.age, final_data.salary,
func.when(final_data.salary.between(mean_salary-2*stddev, mean_salary+2*stddev), final_data.salary)
.otherwise(mean_salary)
.alias("updated_salary")
)
no_outlier.show()
# func中有現成的常用統計函數,更加方便
# 1.計算均值
mean_salary = final_data.select(func.mean('salary')).collect()[0][0]
# 2.計算標準差
final_data.select(func.stddev('salary')).collect()[0][0]
# 離羣值替代就和上面的一致了
7. 重複值
# 重複值的處理,和pandas很像啊
authors = [['Thomas','Hardy','June 2,1840'],
['Thomas','Hardy','June 2,1840'],
['Thomas','H',None],
['Jane','Austen','16 December 1775'],
['Emily',None,None]]
df1 = spark.createDataFrame(authors,schema=["FirstName","LastName","Dob"])
df1.show()
# 刪除重複值行
df1.dropDuplicates().show()
# 只要某一列有重複值,則去重
df1.dropDuplicates(subset=['FirstName']).show()
# pandas的方法
df=pd.DataFrame(authors, columns=["FirstName","LastName","Dob"])
df.drop_duplicates(subset=['FirstName'])
8. 生成新列
# 數據轉換,可以理解成列與列的運算
# 注意自定義函數的調用方式
# 0.創建udf自定義函數,對於簡單的lambda函數不需要指定返回值類型
from pyspark.sql.functions import udf
concat_func = udf(lambda name,age:name+'_'+str(age))
# 1.應用自定義函數
concat_df = final_data.withColumn("name_age", concat_func(final_data.name, final_data.age))
concat_df.show()
# 2.通過列生成另一列
data_new=concat_df.withColumn("age_incremented",concat_df.age+1)
data_new.show()
# 3.某些列是自帶一些常用的方法的
df1.withColumn('Initial', df1.LastName.substr(1,1)).show()
# 4.順便增加一新列
from pyspark.sql.functions import lit
df1.withColumn('newCol', lit(0)).show()
9. 類eval操作
傳入一個操作字符串,然後轉成python代碼執行,就像python的eval一樣。
from pyspark.sql.functions import expr
color_df.select(expr('length(color)')).show()
10. 行的最大最小值
求每一行的最大最小值,相當於axis=1
# 測試數據
df=[(1,1000),(2,2000),(3,3000),(4,4000)]
df=spark.createDataFrame(df, schema=["emp_id","salary"])
df.show()
# 求行的最大最小值
from pyspark.sql.functions import greatest, least
df.select(greatest('emp_id','salary').alias('greatest'),
least('emp_id','salary').alias('least')
).show()
# +--------+-----+
# |greatest|least|
# +--------+-----+
# | 1000| 1|
# | 2000| 2|
# | 3000| 3|
# | 4000| 4|
# +--------+-----+
11. when操作
相當於SQL中的case when 操作
from pyspark.sql.functions import when
# 1.case when age=2 then 3 else 4
df.select(when(df['age'] == 2, 3).otherwise(4).alias("age"))show()
# 2.case when age=2 when age=age+1
df.select(when(df.age == 2, df.age + 1).alias("age")).show()
case when age<2 then age+2 else age end
df.withColumn('age', when(df.age == 2, df.age + 1).otherwise(df2['age'])).show()
12. lag,lead平移
很好用的函數啊,特別是在處理時間序列的時候,和pandas的shift很像。
from pyspark.sql.functions import lag, lead
df = spark.createDataFrame([(1, 2, 3) if i % 2 == 0 else (i, 2 * i, i % 4) for i in range(5)],
["a", "b", "c"])
df.show()
df.select(lag('a', 1, 0).alias('lag')).show()
df.select(lead('a', 1, 0).alias('lag')).show()