DataFrame的基本使用--学习笔记

1,DataFrame的基本使用

DSL方法–DataFrame方法

其中包括的方法有:select(),selectExpr(),groupby()/groupBy() where ,orderBy(),sort(),limit(),withColumn(),

    from pyspark.sql import SparkSession#创建ss对象ss = SparkSession.builder.getOrCreate()# 创建sc对象sc= ss.sparkContext#读取hdfs上的文件数据转换成rdd对象rdd1 = sc.textFile('/test/stu.txt')rdd_split = rdd1.map(lambda x:x.split(','))print(rdd1.take(10))df1 = rdd_split.toDF(schema='id string,name string,gender string,age string,birthday string,major string,hobby string,create_time string')df1.show()df1.printSchema()print('----------------select-----------------------------')#查询所有列数据df1_select = df1.select('*')df1_select.show()#查询指定条目数据print(df1_select.take(5))#查询指定列数据#通过三种方式获取列 '列名' df.列名  df['列名']df_select2 = df1_select.select('id',df1['name'],df1.gender)df_select2.show()#查询列时修改显示列名df_select3 = df1.select(df1['name'].alias('stu_name'),df1.gender.alias('stu_gender'))#通过cast()修改字段类型,格式为df.列名.cast('修改后的列名')df_select4 = df1.select(df1.id.cast('int'),df1.name,df1['age'].cast('int'),df1['gender'],df1['major'],df1['birthday'])#打印数据的数据结构df_select4.printSchema()print('-----------------selectExpr------------------------------')#selectExpr(),写入字符串表达式 和sql代码类似df_select5 = df1.selectExpr('id as user_id','name','gender as stu_gender')df_select5.show()#通过cast修改字段类型df_select6 = df1.selectExpr('cast(id as int)','cast(age as int)')df_select6.printSchema()print('-----------------where------------------------------')#过滤满足条件的数据,减少行数df_where1 = df_select4.where('age>22')df_where1.show()#过滤查询单个过滤条件三种方式df_where0 = df_select4.where('age>22')df_where0.show()df_where2 = df_select4.where(df_select4['name'] == '王刚')df_where2.show()df_where3 = df_select4.where(df_select4.name == '王刚')df_where3.show()#多个过滤条件两种过滤方式df_where4 = df_select4.where('age >22  and name = "王刚"')df_where4.show()df_where5 = df_where4.where((df_select4['age'] > 22) & (df_where4['name']=='王刚'))df_where5.show()# print('---------------------groupBy-------------------------------')# #计算不同性别的平均年龄# #聚合函数获取列名 ->'列名'# #df.toDF(列名1,列名2……)修改列名注意点:写所有的列名,如果不修改也需要写原列名# df_groupby1 = df_select4.groupby('gender').mean('age').toDF('gender','avg_age')## #第二种修改列名的方式# #df_groupby1.select('gender',df_groupby1['avg(age)'].alias('avg_age2')).show()## df_groupby1.show()### df_groupby2 = df_select4.groupby('major','gender').avg('age').toDF('majot','gnder','avg_age')# df_groupby2.show()## print('-------------------------groupby/groupBy  where -------------------')# #分组后加where条件# df_group3_where = df_select4.groupby('major','gender').mean('age').where('avg(age)>21.5')# df_group3_where.show()print('---------------------orderBy/sort 排序 操作---------------------')#对出生日期进行降序排序df_orderby1= df_select4.orderBy('birthday',ascending=False)df_orderby1.show()df_orderby2= df_select4.orderBy('birthday',ascending=True)df_orderby2.show()#对多列进行排序操作df_orderby3 = df_select4.orderBy(['age','birthday'],ascending=[False,True])df_orderby3.show()df_sort1= df_select4.sort('age',ascending=True)df_sort1.show()from pyspark.sql.functions import *#方法来自于导入模块df_sort3 = df_select4.sort(desc('age'),asc('birthday'))df_sort3.show()print('--------------limit----------------------------------')#打印展示指定条目数局的df对象"""limit和show区别:limit生成新的df行数据由num确定show展示的一个行数据,不是df中的行数  df有100行数据,可以通过show方法展示其中给你前30行数据"""#默认展示二十行数据df_select4.show(n=30)#truncate:是否进行折叠省略,默认折叠True,False不折叠/不省略df_select4.show(truncate=False)  #不省略df_limit = df_select4.limit(num=10)df_limit.show()print('-----------withColumn新增列--------------------')#第一个参数:新列名#第二个参数:新列的计算逻辑df_withcolumn = df_select4.withColumn('name_age',df_select4['age']+10)df_withcolumn.show()#新增一列常熟列F.lit()中from pyspark.sql import functions as Fdf_withcolumn2 = df_select4.withColumn('new_age',F.lit('10'))df_withcolumn2.show()#withColumnRenamed#第一个参数员列名#第二个参数:新列名"""修改列名方式①df.select(df['列名'].alias('新列明'))②df.toDF(列名1,列名2,……)③df.withColumnRenamed(原列名,新列名)"""df_withcolumnRenamed = df_select4.withColumnRenamed('age','new_age1')df_withcolumnRenamed.show()

sql语句的方式

其中包括的执行步骤为:

①先创建ss对象,再根据ss.sparkContext创建sc对象

②通过sc获取hdfs上的数据

③在对数据进行格式转换后,再将数据转为dataFrame结构

④再通过df创建一张表,给定表名

⑤在根据sql语句查询自己需要的数据

  from pyspark.sql import SparkSession#创建ss对象ss = SparkSession.builder.getOrCreate()# 创建sc对象sc= ss.sparkContext#读取hdfs上的文件数据转换成rdd对象rdd1 = sc.textFile('/test/stu.txt')rdd_split = rdd1.map(lambda x:x.split(','))print(rdd1.take(10))df1 = rdd_split.toDF(schema='id string,name string,gender string,age string,birthday string,major string,hobby string,create_time string')df1.show()df1.printSchema()#第一步:将需要处理的df对象映射成一张表  命名一个表名#表名随意df1.createTempView('stu')#第二部:执行sql语句df2 = ss.sql('select cast(id as string),name as user_name,gender,age  from stu where age>22')df2.show()

2,DSL方法–join

    #join关联方法# 多个df的关联操作from pyspark.sql import SparkSessionfrom pyspark.sql.types import *# 生成SparkSession对象ss = SparkSession.builder.getOrCreate()# SparkSession中可以通过sparkContext获取sparkContext对象sc = ss.sparkContext# 生成rddrdd1 = sc.parallelize([[1, 'zhangsan', 20],[2, 'lisi', 20],[3, 'wangwu', 22]])rdd2 = sc.parallelize([[3, 'zhaoliu', 20],[4, 'xiaoming', 21],[5, 'itcast', 22]])# 定义schema信息schema_type = StructType(). \add('id', IntegerType()). \add('name', StringType()). \add('age', IntegerType(), False)# toDF 将二维rdd数据转为dataframe数据df1 = rdd1.toDF(schema_type)df2 = rdd2.toDF(schema_type)df1.show()df2.show()#on:关联条件如果两个dff的字段名相同可以直接使用列名 ->可以有多个关联条件#how:关联方式,默认是inner,内连接#df_join中只有id相同的关联成功,且只显示关联成功的df_innerjoin = df1.join(df2,on='id',how='inner')df_innerjoin.show()#df_join中有两个关联字段df_join2 = df1.join(df2,on=df1.id == df2.id)df_join2.show()#结果# | id|  name|age| id|   name|age|# +---+------+---+---+-------+---+# |  3|wangwu| 22|  3|zhaoliu| 20|#左连接 how = 'left'df_leftjoin = df1.join(df2,on=['id'],how='left')df_leftjoin.show()#如果不指定how那么默认是innerjoin 内连接df_leftjoin2 = df1.join(df2,on=df1.id == df2.id,how='left')df_leftjoin2.show()#右连接df_right_join = df1.join(df2,on=['name'],how='right')df_right_join.show()#满外连接how = fulldf_full_joinn = df1.join(df2,on='id',how='full')df_full_joinn.show()#交叉连接,笛卡尔积(3X3=9条数据)df_cross_join = df1.crossJoin(df2)df_cross_join.show()

3,DSL-数据清洗

其中包括的方法有:toDF 将二维rdd数据转为dataframe数据,null值处理填充fillna(),删除dropna(),去重dropDuplicates()

    #join关联方法# 多个df的关联操作from pyspark.sql import SparkSessionfrom pyspark.sql.types import *# 生成SparkSession对象ss = SparkSession.builder.getOrCreate()# SparkSession中可以通过sparkContext获取sparkContext对象sc = ss.sparkContext# 生成rddrdd1 = sc.parallelize([[1, 'zhangsan', 20],[2, 'lisi', 20],[3, 'wangwu', 22]])rdd2 = sc.parallelize([[3, 'zhaoliu', 20],[4, 'xiaoming', 21],[5, 'itcast', 22]])# 定义schema信息schema_type = StructType(). \add('id', IntegerType()). \add('name', StringType()). \add('age', IntegerType(), False)# toDF 将二维rdd数据转为dataframe数据df1 = rdd1.toDF(schema_type)df2 = rdd2.toDF(schema_type)df1.show()df2.show()df_innerjoin = df1.join(df2,on='id',how='left')df_innerjoin.show()#df.drop()df_drop = df_innerjoin.drop('name')df_drop.show()#删除多列数据df_drop2 = df_innerjoin.drop('id','name')df_drop2.show()#null处理:#①填充,使用值对null值进行替换# ②删除,删除null值行数据#填充null值#常数值->常数值类型是什么就是对df中对应的类型列进行填充,常熟值是数值类型,对df数值列进行填充df_fillnal1 = df_innerjoin.fillna(100)df_fillnal1.show()df_fillnam2 = df_innerjoin.na.fill('小明')df_fillnam2.show()df_fillnal3 = df_innerjoin.toDF('id','name','age','name_2','age_2').fillna(value={'age_2':100,'name_2':'小明'})df_fillnal3.show()df_fillnal4 = df_innerjoin.toDF('id','name','age','name_2','age_2').fillna(value=100,subset=['name_2','age_2'])df_fillnal4.show()#删除数据行#hoe:any,任意列值为null就要删除行数据  all所有列值为null才删除行数据df_dropna1 = df_innerjoin.toDF('id','name','age','name_2','age_2').dropna(how='any')df_dropna1.show()df_dropn2 = df_innerjoin.toDF('id','name','age','name_2','age_2').dropna(how='all')df_dropn2.show()df_dropna3 = df_innerjoin.toDF('id','name','age','name_2','age_2').dropna(thresh=2)df_dropna3.show()#交叉连接,笛卡尔积(3X3=9条数据)df_cross_join = df1.crossJoin(df2)df_cross_join.show()#去重->去除重复的行数据#subset:指定去重的列,不指定是对所有列进行去重df_dropDuplicates1 = df_cross_join.dropDuplicates()df_dropDuplicates1.show()#指定subset[]df_dropDuplicates2 = df_cross_join.toDF('id','name','age','id_2','name_2','age_2').dropDuplicates(subset=['id','name','age'])df_dropDuplicates2.show()

4,内置函数

4.1字符串函数

包含的方法有:concat(),concat_ws(),split(),substring(),substring_index(),replace(),regexp_extract()

    # DF的内置函数# DF的数据是结构化数据,所以DSL方法和SQL的关键字基本一致# todo:导入内置函数模块,as命名别称F 使用模块时可以用F表示from pyspark.sql import SparkSession, functions as F# 创建SparkSession对象ss = SparkSession.builder.getOrCreate()# 使用sparkcontext读取hdfs上的文件数据sc = ss.sparkContext# 将读取的文件数据转化为rddrdd = sc.textFile('hdfs://node1:8020/test/stu.txt')res1 = rdd.collect()print(f'rdd文件数据:{res1}')# 将每行字符串数据切割转为二维rddrdd_split = rdd.map(lambda x: x.split(','))res2 = rdd_split.collect()print(f'切割后的rdd数据:{res2}')# 将rdd转为df数据df = rdd_split.toDF(schema='id string,name string,gender string,age string ,birthday string,major string,hobby string,create_time string')# 查看转化的df数据df.show()print('---------------------concat/concat_ws 拼接----------')#concat(列名1,列名2,……)df_concat1 = df.select(F.concat('name',df.gender,df['age']))df_concat1.show()#conat_ws(拼接符,列名1,列名2)df_concatws2 = df.select(F.concat_ws('-','name',df.gender,df['age']))df_concatws2.show()print('---------splilt----------------')#split(列名,分隔符),以指定分隔符对字符串列的数据进行分割操作,返回列表# def_split = df.select(F.split('birthday','-').alias('new_col'))def_split = df.select(F.split('birthday','-')[0].alias('year'),F.split('birthday','-')[1].alias('month'),F.split('birthday','-')[2].alias('day'))def_split.show()df_split2 = df.select(F.split('birthday','-',limit=11))df_split2.show()df_split3 = df.select(F.split('birthday','-',limit=2))print('-------------------substring/substring_index截取字符串-------------')#substring(列名,起始位置,截取长度) ->从起始位置截取指定长度的子串#其实位置从1开始,0,1的效果是一样的df.select(F.substring('birthday',0,4)).show()df.select(F.substring('birthday',1,4)).show()#substring_index(列名,截取符,第n个截取符号)#n:正数,从左往右数截取符,截取左侧部分#n:负数,从右往左数截取符df.select(F.substring_index('birthday','-',1)).show()df.select(F.substring_index('birthday','-',2)).show()df.select(F.substring_index('birthday','-',-1)).show()df.select(F.substring_index('birthday','-',-2)).show()

6.2日期时间函数

   # DF的内置函数# DF的数据是结构化数据,所以DSL方法和SQL的关键字基本一致# todo:导入内置函数模块,as命名别称F 使用模块时可以用F表示from pyspark.sql import SparkSession, functions as F# 创建SparkSession对象ss = SparkSession.builder.getOrCreate()# 使用sparkcontext读取hdfs上的文件数据sc = ss.sparkContext# 将读取的文件数据转化为rddrdd = sc.textFile('hdfs://node1:8020/test/stu.txt')res1 = rdd.collect()# print(f'rdd文件数据:{res1}')# 将每行字符串数据切割转为二维rddrdd_split = rdd.map(lambda x: x.split(','))res2 = rdd_split.collect()# print(f'切割后的rdd数据:{res2}')# 将rdd转为df数据df = rdd_split.toDF(schema='id string,name string,gender string,age string ,birthday string,major string,hobby string,create_time string')# 查看转化的df数据# df.show()print('--------------------------------获取当前时间-------------------------')#获取年月日df.select(F.current_date()).show()#获取年月日时分秒毫秒#truncate=False 取消省略df.select(F.current_timestamp()).show(truncate=False)#获取时间戳df.select(F.unix_timestamp()).show()print('--------------------------------日期时间转换-------------------------')#date_format(日期时间类型列,格式)#y 年 M:月 d:天 H:时 m:分 s:秒df.select(F.date_format('birthday','MM/dd/yyyy')).show()print('--------------------------------#时间戳转换成日期时间-------------------------')#from_unixtime(时间戳类型列,格式)df_timestamp = df.select(F.current_timestamp())df.select(F.from_unixtime('create_time','yyyy-MM-dd')).show(truncate=False)print('--------------------------------时间取值-------------------------')#获取年df.select(F.year('birthday')).show()# 获取月份month()df.select(F.month('birthday')).show()#获取日df.select(F.dayofmonth('birthday')).show()#获取当前年份第多少天df.select(F.dayofyear('birthday')).show()#获取当前星期第多少天0-6,1是周日df.select(F.dayofweek('birthday')).show()#获取当前月1的最后一天日期df.select(F.last_day('birthday')).show()print('--------------------------------#时间加减-------------------------')#date_sub(日期时间类型列,天数) 减少多少天df.select(F.date_sub(F.current_date(),10)).show()#date_add(日期时间类型列,天数)加多少天df.select(F.date_add(F.current_date(),10)).show()#datediff(结束日期,开始日期)做差,获取天数差值df.select(F.datediff(F.current_date(),'birthday')).show()

6.3聚合函数

  # DF的内置函数# DF的数据是结构化数据,所以DSL方法和SQL的关键字基本一致# todo:导入内置函数模块,as命名别称F 使用模块时可以用F表示from pyspark.sql import SparkSession, functions as F# 创建SparkSession对象ss = SparkSession.builder.getOrCreate()# 使用sparkcontext读取hdfs上的文件数据sc = ss.sparkContext# 将读取的文件数据转化为rddrdd = sc.textFile('hdfs://node1:8020/test/stu.txt')res1 = rdd.collect()# print(f'rdd文件数据:{res1}')# 将每行字符串数据切割转为二维rddrdd_split = rdd.map(lambda x: x.split(','))res2 = rdd_split.collect()# print(f'切割后的rdd数据:{res2}')# 将rdd转为df数据df = rdd_split.toDF(schema='id string,name string,gender string,age string ,birthday string,major string,hobby string,create_time string')# 查看转化的df数据# df.show()print('--------------------------------agg聚合函数-------------------------')#functions模块中的聚合函数要结合agg函数一起使用df_agg = df.groupby('gender').agg(F.sum(df.age.cast('int')).alias('sum_data'))df_agg.show()df_select = df.select(df.id.cast('int'),df.name,df['gender'],df['age'].cast('int'),df.birthday,df.major,df.hobby,df.create_time)#聚合函数#对某列进行聚合操作,返回一个值df_select.select(F.sum('age')).show()#分组聚合# count()不需要写列名df_select.groupby('gender').count().show()#内置函数中的聚合函数可以和agg函数结合使用#对一列进行分组聚合操作df_select.groupby('gender').agg(F.count('id').alias('cnt')).show()#对多列进行分组聚合操作#round(列名,位数) ->保留几位小数df_select.groupby('gender').agg(F.count('id').alias('cnt'),F.round(F.avg('age'),2).alias('avg_age'),F.max('age').alias('max_age')).show()#{key:value}->key:聚合字段名,value:聚合函数名df_select.groupby('gender').agg({'id':'count','age':'mean'}).show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/631792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

命令行参数环境变量和进程空间地址

文章目录 命令行参数环境变量进程地址空间 正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂,风趣幽默,忍不住分享一下给大家。 点击跳转到网站。 命令行参数 什么是命令行参数? 我…

【第二十二节】变量与运算符-位运算符

运算符运算<<左移>>右移>>>无符号右移&与运算|或运算^异或运算~取反运算 位运算符详细信息 <<空位补0&#xff0c;被遗弃的高位丢弃&#xff0c;空缺位补0>>被移位的二进制最高位为0&#xff0c;右移后&#xff0c;空缺位补0&#xff0…

Fine-tuning:个性化AI的妙术

在本篇文章中,我们将深入探讨Fine-tuning的概念、原理以及如何在实际项目中运用它,以此为初学者提供一份入门级的指南。 一、什么是大模型 ChatGPT大模型今年可谓是大火,在正式介绍大模型微调技术之前,为了方便大家理解,我们先对大模型做一个直观的抽象。 本质上,现在…

存储任意类型

code /* * c17 std::any */#include <cstdint> #include <cstring> #include <cstdlib> #include <iostream> #include <thread> #include <chrono>namespace lxz {// T不为指针时 template<typename T> struct Data {Data(): data…

运用分布式锁 redisson

导入依赖 根据springboot版本不同自行选择版本 <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.15.3</version> </dependency> 创建客户端 Beanpublic R…

面试的忌讳,你中了几枪?

面试是职场旅程中的一个重要环节&#xff0c;它不仅是求职者展示自己的一个舞台&#xff0c;也是企业寻找合适人才的一个过程。在这个过程中&#xff0c;有几个常见的误区需要特别注意。 夜郎自大 很多仗着自己有几年的工作经验&#xff0c;总觉得自己技术牛逼&#xff0c;面…

QT第六天

要求&#xff1a;使用QT绘图&#xff0c;完成仪表盘绘制&#xff0c;如下图。 素材 运行效果&#xff1a; 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPainter> #include <QPen>QT_BEGIN_NAMESPACE name…

网络端口映射和端口转发的区别和联系

目 录 一、端口映射技术 1.1 原理 1.2 应用场景 1、远程访问 2、游戏主机 3、文件共享 4、监控视频共享 二、端口转发技术 2.1 原理 2.2 应用场景 1、网络负载均衡 2、网络安全 3、网络代理 三、端口映射和转发的实现方法 3.1 路由器配置 3.2 网络防火墙 …

跨平台兼容,无限可能:Apple Remote Desktop for Mac让远程控制更简单

Apple Remote Desktop for Mac是一款远程桌面管理软件&#xff0c;提供了一系列强大的功能&#xff0c;让用户可以轻松地管理和控制远程计算机。以下是该软件的一些主要功能和特点&#xff1a; 实时远程访问和控制&#xff1a;使用Apple Remote Desktop&#xff0c;用户可以在…

跟着pink老师前端入门教程-day05

七、CSS的引入方式 根据CSS样式书写的位置&#xff08;或者引入的方式&#xff09;&#xff0c;CSS样式表可以分为三大类 1. 行内样式表&#xff08;行内式&#xff09; 内部样式表&#xff08;内嵌样式表&#xff09;是写到HTML页面内部&#xff0c;将所有的CSS代码抽取出…

【Proteus仿真】【Arduino单片机】智能助眠机系统设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用蜂鸣器闹铃模块、LCD1602显示模块、心率血氧模块、ADC模块、按键模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示传感器采…

HackTheBox - Medium - Linux - Mentor

Mentor Mentor 是一台中等难度的 Linux 机器&#xff0c;其路径包括在到达 root 之前在四个不同的用户之间切换。使用可暴力破解的社区字符串扫描“SNMP”服务后&#xff0c;会发现用于“API”端点的明文凭据&#xff0c;该端点被证明容易受到盲目远程代码执行的影响&#xff…

2. 分享三篇早期的FPGA 布局布线论文

1. PathFinder:一种基于协商和性能驱动的FPGA布线器 Larry MCMURCHIE, Carl EBELING. PathFinder: A Negotiation-Based Performance-Driven Router for FPGAs, February 1996[J/OL]. February 1996 针对FPGA布线中存在的布线性能与可布通性之间的矛盾&#xff0c;该文提出了…

JAVA代码学习(中)

2023年将会持续于B站、CSDN等各大平台更新&#xff0c;可加入粉丝群与博主交流:838681355&#xff0c;为了老板大G共同努力。 【商务合作请私信或进群联系群主】 四、继承、多态 继承机制的使用可以复用一些定义好的类&#xff0c;减少重复代码的编写。多态机制可以动态调整对…

2024年1月18日Arxiv最热NLP大模型论文:Large Language Models Are Neurosymbolic Reasoners

大语言模型化身符号逻辑大师&#xff0c;AAAI 2024见证文本游戏新纪元 引言&#xff1a;文本游戏中的符号推理挑战 在人工智能的众多应用场景中&#xff0c;符号推理能力的重要性不言而喻。符号推理涉及对符号和逻辑规则的理解与应用&#xff0c;这对于处理现实世界中的符号性…

如何实现无公网ip远程访问内网本地BUG管理服务【内网穿透】

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

精通Discord营销:多账号注册与管理,高效打造矩阵

Discord虽然是一个海外小众平台&#xff0c;但在Z世代群体来说却非常受欢迎。通常在游戏行业、年轻化的电商特定品类、软件等业务中&#xff0c;Discord的社群营销可以起到非常卓越的效果。但是&#xff0c;您必须学会管理不同的帐户&#xff0c;以构成矩阵打造社区&#xff0c…

更适合3D项目的UI、事件交互!纯国产数字孪生引擎持续升级中!!!

UI和事件交互是3D可视化项目中最常见的模块&#xff0c;主要用于信息添加、展示&#xff0c;用来确保按照用户需求呈现内容并完成交互。 平时工作在进行UI和交互设计时&#xff0c;经常出现以下问题&#xff1a;UI过于复杂导致3D项目内交互效率低下&#xff0c;或者是结合3D项目…

简单了解【多智能体强化学习(MARL)】

我们的现实生活中有着许多多智能体共同决策的场景&#xff0c;比如多机械臂协同&#xff0c;多个无人机或多个机器人完成某共同目标。下面介绍单智能体强化学习的进化&#xff0c;多智能体强化学习。 含义 多智能体系统中包含 m 个智能体&#xff0c;智能体共享环境&#xff…

【vsan数据恢复】vsan逻辑架构出现故障的数据恢复案例

VSAN数据恢复环境&#xff1a; 一套有三台服务器节点的VSAN超融合基础架构&#xff0c;每台服务器节点上配置2块SSD硬盘和4块机械硬盘。 每个服务器节点上配置有两个磁盘组&#xff0c;每个磁盘组使用1个SSD硬盘作为缓存盘&#xff0c;2个机械硬盘作为容量盘。三台服务器节点上…