Scala:如何使用Scala替换Dataframes中的值

38

例如,我想在一个列中将所有等于0.2的数字替换为0。在Scala中该怎么做?谢谢。

编辑:

|year| make|model| comment            |blank|
|2012|Tesla| S   | No comment         |     | 
|1997| Ford| E350|Go get one now th...|     | 
|2015|Chevy| Volt| null               | null| 

这是我的数据框,我想将“制造商”列中的“特斯拉”更改为“S”


如果是0.2,将map命令更改为0是什么? - Tong
我该如何专注于特定的列? - Tong
编辑您的初始帖子,包括上述信息。 - ccheneson
所以最终,您期望在您的示例中的第一个数据中得到 |2012|S| S| 吗? - ccheneson
是的。抱歉格式混乱。 - Tong
显示剩余7条评论
6个回答

49

使用Spark 1.6.2,Java代码(抱歉),这将在不通过RDD的情况下更改整个数据框中“Tesla”出现的所有实例为“S”:

Spark 1.6.2,Java代码(抱歉),这将在不通过RDD的情况下更改整个数据框中“Tesla”出现的所有实例为“S”:

dataframe.withColumn("make", when(col("make").equalTo("Tesla"), "S")
                             .otherwise(col("make") 
                    );

编辑后添加@marshall245的“otherwise”,以确保非特斯拉列不被转换为NULL。


嘿,伙计,如果我想用另一个数据框的列值来更改一个列(两个数据框都有一个ID列),我似乎无法在Java Spark中实现。 - Vasile Surdu
这个问题最好用select...join on id来解决,听起来像是一个新问题。希望能帮到你。 - Azeroth2b
为什么要编辑这个并将其作为与@marshall245相同的答案? - Eduardo Reis
我在哪里可以找到withColumn函数的文档?实际上,我有更多的条件和要更改值的列。我已经查看了https://docs.azuredatabricks.net/spark/1.6/sparkr/functions/withColumn.html,但这并没有帮助。有人能帮忙吗? - GadaaDhaariGeek
这可能是一个新问题。您可以链接数据框命令。例如,您可以执行dataframe.withcolumn(...).withcolumn(...).<其他事情>。每次调用都会返回一个新的数据框,根据命令对原始数据框进行变异。 - Azeroth2b

30

在@Azeroth2b的解决方案基础上进行改进。如果您只想替换其中几个项目并保留其余部分不变,请执行以下操作。如果不使用otherwise(...) 方法,则列的其余部分将变为null。

import org.apache.spark.sql.functions._

val newsdf =
  sdf.withColumn(
    "make",
    when(col("make") === "Tesla", "S").otherwise(col("make"))
  );

旧的数据框

+-----+-----+ 
| make|model| 
+-----+-----+ 
|Tesla|    S| 
| Ford| E350| 
|Chevy| Volt| 
+-----+-----+ 

新数据框

+-----+-----+
| make|model|
+-----+-----+
|    S|    S|
| Ford| E350|
|Chevy| Volt|
+-----+-----+

15

使用用户定义函数 (udf) 可以在数据框中实现此操作。

import org.apache.spark.sql.functions._
val sqlcont = new org.apache.spark.sql.SQLContext(sc)
val df1 = sqlcont.jsonRDD(sc.parallelize(Array(
      """{"year":2012, "make": "Tesla", "model": "S", "comment": "No Comment", "blank": ""}""",
      """{"year":1997, "make": "Ford", "model": "E350", "comment": "Get one", "blank": ""}""",
      """{"year":2015, "make": "Chevy", "model": "Volt", "comment": "", "blank": ""}"""
    )))

val makeSIfTesla = udf {(make: String) => 
  if(make == "Tesla") "S" else make
}
df1.withColumn("make", makeSIfTesla(df1("make"))).show

1
我猜这会提高性能,因为您没有将 DataFrame 转换为 RDD 并添加新列。 - Nandakishore
这不会导致重复的“make”列吗? - WestCoastProjects
1
@javadba 不会,withColumn 会在列不存在时创建新的列,或者替换现有的列。https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.sql.Dataset https://spark.apache.org/docs/1.6.0/api/scala/index.html#org.apache.spark.sql.DataFrame - Tony

13
注意:正如Olivier Girardot所提到的,这个答案并不是最优解,withColumn解决方案才是应该使用的(Azeroth2b的答案)

无法删除已被接受的答案。


以下是我的看法:

 val rdd = sc.parallelize(
      List( (2012,"Tesla","S"), (1997,"Ford","E350"), (2015,"Chevy","Volt"))
  )
  val sqlContext = new SQLContext(sc)

  // this is used to implicitly convert an RDD to a DataFrame.
  import sqlContext.implicits._

  val dataframe = rdd.toDF()

  dataframe.foreach(println)

 dataframe.map(row => {
    val row1 = row.getAs[String](1)
    val make = if (row1.toLowerCase == "tesla") "S" else row1
    Row(row(0),make,row(2))
  }).collect().foreach(println)

//[2012,S,S]
//[1997,Ford,E350]
//[2015,Chevy,Volt]
你实际上可以直接在 DataFrame 上使用 `map`。因此,你基本上要检查列 1 是否为字符串 `tesla`。 如果是 `tesla`,则将 `make` 的值设置为 `S`,否则保留列 1 的当前值。然后,使用索引(从零开始)(例如,在我的示例中为 `Row(row(0), make, row(2))`)构建包含行中所有数据的元组。可能有更好的方法来完成这个任务。我对 Spark 还不是很熟悉。

谢谢你的帮助。我还有一个问题。你的解决方案可以打印出我想要的字符串。但是,如果我想要更改数据框内部的值怎么办?当我执行dataframe.show()时,值仍然是tesla。 - Tong
2
数据框架基于不可变的RDD。尝试使用以下代码val newDF = dataframe.map(row => { val row1 = row.getAs[String](1) val make = if (row1.toLowerCase == "tesla") "S" else row1 Row(row(0),make,row(2)) })构建新的数据框架。 - ccheneson
嗨!首先感谢您解决我的问题。我可以仅通过 .rdd 将 DataFrame 转换为 RDD 吗?是否存在像更改模式这样的风险?再次感谢! - Tong
使用toDF()RDD转换为DataFrame - ccheneson
4
这会破坏Spark的Catalyst优化,因此不是最佳实践,使用withColumn方法最适合这种情况。 - Olivier Girardot
显示剩余6条评论

3

df2.na.replace("Name",Map("John" -> "Akshay","Cindy" -> "Jayita")).show()

在 DataFrameNaFunctions 类型的 [T] 中使用 replace 函数,参数为字符串类型的列名 col 和替换映射表 replacement: Map[T,T]。

运行此函数需要激活 spark 对象并且 dataframe 必须包含 headers。


这个答案并不是为了 OP 的使用情况而写的,但它是完成任务最简单的方法。你需要 import org.apache.spark.sql.DataFrameNaFunctions - Tony

0
import org.apache.spark.sql.functions._

val base_optin_email = spark.read.option("header","true").option("delimiter",",").schema(schema_base_optin).csv(file_optin_email).where("CPF IS NOT NULL").
        withColumn("CARD_KEY",  lit(translate( translate(col("cpf"), ".", ""),"-","")))

2
欢迎来到 Stack Overflow。仅代码回答通常可以通过添加一些解释说明它们的工作方式和原理而得到改善。当回答一个已有被接受答案的四年前的问题时,非常重要的是指出你的答案涉及哪个问题的新方面。请使用编辑器中带有花括号按钮的格式化代码。 - Jason Aller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接