pyspark dataframe实现行循环,调用Python 实现大批量小文件处理,对大批量用户实现用户画像

pyspark dataframe实现行循环,调用Python 实现大批量小文件处理,对大批量用户实现用户画像


适合应用场景
集群处理大批量的小文件,如需要对1000万用户构建用户画像,每个用户的数据不大有几百M(单机Python能处理的程度),可以这么调用,而且之前写的单Python代码直接复制粘贴稍微改动就可以直接用
直接上代码

# -*- coding: utf-8 -*- 
# @Time : 2019/6/6 10:40 
# @Author : WP
from pyspark.sql.session import SparkSession
import os
import pandas as pd
import numpy as np
# spark初始化
spark = SparkSession\
        .builder \
        .appName("Dataframe_circ")\
        .getOrCreate()
sc = spark.sparkContext
# 不显示日志,只显示Java报错日志
sc.setLogLevel('ERROR')

"""按vid进行分组"""


def build(r):
    """

    :param r: spark dataframe 行
    :return: 键值对
    """
    r = r.asDict() if type(r) is not dict else r
    resultkey = r["VID"]
    # spark dataframe按行存为字典
    resultvalue = {}
    for key in r.keys():
        resultvalue[key] = r[key]
    return (resultkey, resultvalue)


"""根据key对数据进行合并"""


def merge(x, y):

    """

    :param x: 键值对
    :param y: 键值对
    :return: vid为key的列表
    """
    # 在每个节点执行完后执行
    if isinstance(x, list) and isinstance(y, list):
        x.extend(y)
        return x
    elif isinstance(x, list):
        x.append(y)
        return x
    elif isinstance(y, list):
        y.append(x)
        return y
    # 最先执行,最开始x,y都不为list
    elif x and y:
        return [x, y]
    elif x:
        return [x]
    else:
        return [y]


"""map分开处理每个VOD的数据,若添加Python 函数在此函数添加"""


def make_dataframe(data):
    """

    :param data:VID为关键字的列表
    :return: 对应处理后的VID数据
    """
    c_data = pd.DataFrame(data[1] if type(data[1]) == list else [data[1]])
    data_need = c_data[c_data["size"] > 5]
    data_need = data_need.reset_index(drop=True)
    return p_spark(data_need)


"""python dataframe 转 spark rdd"""


def p_spark(data):
    """

    :param data: 每个 vid 对应的python dataframe
    :return: 每个 VID 的 list
    """
    # 把每个VID 的 Python dataframe的所有行以字典形式存在list中
    list_all = []
    for i in range(len(data)):
        # 提取Python dataframe的每一行存为字典格式
        dict_need = dict(data.loc[i, :])
        for key in dict_need.keys():
            # 因spark dataframe的编码格式不支持np的数据格式需要对np的数据进行重新编码
            if isinstance(dict_need[key], (np.float64, np.float32, np.float)):
                dict_need[key] = float(dict_need[key])
            elif isinstance(dict_need[key], (np.int64, np.int, np.int32)):
                dict_need[key] = int(dict_need[key])
        list_all.append(dict_need)
    return list_all


if __name__ == '__main__':
    data_l = [[1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],
              [5, 8, 10, 4, 6, 10, 20, 5, 9, 2, 2]]
    data_l = [{"VID": data_l[0][i], "size": data_l[1][i]} for i in range(len(data_l[0]))]
    # 创建pyspark dataframe
    data_d = spark.createDataFrame(data_l)
    data_d.show()
    # 创建每个id对应的列表
    data_rdd = data_d.rdd.map(lambda r: build(r)).reduceByKey(merge)
    print("pyspark dataframe 转为rdd")
    # 集群数据记得删除collect,内存会爆de
    print(data_rdd.collect())
    # 对每个id对应的数据通过Python 的dataframe的函数进行处理
    data_t = data_rdd.flatMap(lambda k: make_dataframe(k))
    print("经过单节点的Python处理过的数据")
    print(data_t.collect())
    data_all = spark.createDataFrame(data_t)
    data_all.show()

说明
data_d = spark.createDataFrame(data_l)
这里为创建的spark dataframe 样例,模拟大批量需要处理的小文件,两列一列vid,一列size,集群数据读取直接读取为dataframe
这里为创建的spark dataframe 样例,模拟大批量需要处理的小文件
这里为data_rdd 通过data_d转换而来,一个大列表,内容为键值对,每个键值对的id 为 vid,内容为vid 对应的所有数据,为列表形式可以通过map直接用pandas 的 dataframe进行处理
[(1, [{‘VID’: 1, ‘size’: 5}, {‘VID’: 1, ‘size’: 8}, {‘VID’: 1, ‘size’: 10}]), (2, [{‘VID’: 2, ‘size’: 4}, {‘VID’: 2, ‘size’: 6}, {‘VID’: 2, ‘size’: 10}, {‘VID’: 2, ‘size’: 20}]), (3, [{‘VID’: 3, ‘size’: 9}, {‘VID’: 3, ‘size’: 2}, {‘VID’: 3, ‘size’: 2}, {‘VID’: 3, ‘size’: 5}])]

make_dataframe函数里面就是调用 Python 的 pandas dataframe 对数据进行处理,这里我仅仅是对每个vid进行了筛选size>5的行,在进行处理的时候大家只需要把以前的单机Python代码复制粘贴过来即可,这是在处理过程中打印出来的pd 的 dataframe,spark的dataframe的操作不如Python的dataframe方便,而且大家基本都是先学的Python 再接触的spark,对spark的了解不如Python深刻,这样就可以很好的把Python和spark进行结合。这样Python的机器学习的包,深度学习的包也都可以调用了。
单机Pythondataframe
函数 p_spark主要实现把python dataframe处理完的数据存为列表形式 再变为rdd
data_t的输出数据
[{‘VID’: 1, ‘size’: 8}, {‘VID’: 1, ‘size’: 10}, {‘VID’: 2, ‘size’: 6}, {‘VID’: 2, ‘size’: 10}, {‘VID’: 2, ‘size’: 20}, {‘VID’: 3, ‘size’: 9}]
把data_t的数据再创建为spark的dataframe 即可再进行数据写出了,按照vid进行分包,或者什么其他格式都可以了。
这是处理完成过后的数据的saprk dataframe
处理完成的dataframe
过程到此结束,作者水平有限,大家发现什么问题也请大家留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值