python - Pandas to PySpark:将一列元组列表转换为每个元组项的单独列
问题描述
我需要转换一个 DataFrame,其中一个列由一个元组列表组成,每个元组中的每个项目都必须是一个单独的列。
这是 Pandas 中的示例和解决方案:
import pandas as pd
df_dict = {
'a': {
"1": "stuff", "2": "stuff2"
},
"d": {
"1": [(1, 2), (3, 4)], "2": [(1, 2), (3, 4)]
}
}
df = pd.DataFrame.from_dict(df_dict)
print(df) # intial structure
a d
1 stuff [(1, 2), (3, 4)]
2 stuff2 [(1, 2), (3, 4)]
# first transformation, let's separate each list item into a new row
row_breakdown = df.set_index(["a"])["d"].apply(pd.Series).stack()
print(row_breakdown)
a
stuff 0 (1, 2)
1 (3, 4)
stuff2 0 (1, 2)
1 (3, 4)
dtype: object
row_breakdown = row_breakdown.reset_index().drop(columns=["level_1"])
print(row_breakdown)
a 0
0 stuff (1, 2)
1 stuff (3, 4)
2 stuff2 (1, 2)
3 stuff2 (3, 4)
# second transformation, let's get each tuple item into a separate column
row_breakdown.columns = ["a", "d"]
row_breakdown = row_breakdown["d"].apply(pd.Series)
row_breakdown.columns = ["value_1", "value_2"]
print(row_breakdown)
value_1 value_2
0 1 2
1 3 4
2 1 2
3 3 4
这是熊猫解决方案。我需要能够做同样的事情,但使用 PySpark (2.3)。我已经开始研究它,但立即陷入困境:
from pyspark.context import SparkContext, SparkConf
from pyspark.sql.session import SparkSession
conf = SparkConf().setAppName("appName").setMaster("local")
sc = SparkContext(conf=conf)
spark = SparkSession(sc)
df_dict = {
'a': {
"1": "stuff", "2": "stuff2"
},
"d": {
"1": [(1, 2), (3, 4)], "2": [(1, 2), (3, 4)]
}
}
df = pd.DataFrame(df_dict)
ddf = spark.createDataFrame(df)
row_breakdown = ddf.set_index(["a"])["d"].apply(pd.Series).stack()
AttributeError: 'DataFrame' object has no attribute 'set_index'
显然,Spark 不支持索引。任何指针表示赞赏。
解决方案
这可能会:
from pyspark.context import SparkContext, SparkConf
from pyspark.sql.session import SparkSession
from pyspark.sql import functions as F
import pandas as pd
conf = SparkConf().setAppName("appName").setMaster("local")
sc = SparkContext(conf=conf)
spark = SparkSession(sc)
df_dict = {
'a': {
"1": "stuff", "2": "stuff2"
},
"d": {
"1": [(1, 2), (3, 4)], "2": [(1, 2), (3, 4)]
}
}
df = pd.DataFrame(df_dict)
ddf = spark.createDataFrame(df)
exploded = ddf.withColumn('d', F.explode("d"))
exploded.show()
结果:
+------+------+
| a| d|
+------+------+
| stuff|[1, 2]|
| stuff|[3, 4]|
|stuff2|[1, 2]|
|stuff2|[3, 4]|
+------+------+
我觉得为此使用 SQL 更舒服:
exploded.createOrReplaceTempView("exploded")
spark.sql("SELECT a, d._1 as value_1, d._2 as value_2 FROM exploded").show()
重要提示:使用_1
and_2
访问器的原因是 spark 将元组解析为结构并为其提供默认键。如果在您的实际实现中数据框包含一个array<int>
,您应该使用[0]
语法。
最终结果是:
+------+-------+-------+
| a|value_1|value_2|
+------+-------+-------+
| stuff| 1| 2|
| stuff| 3| 4|
|stuff2| 1| 2|
|stuff2| 3| 4|
+------+-------+-------+
推荐阅读
- jquery - 使用字符串作为名称创建对象数组,然后使用字符串引用数组
- ios - 在保持框架不变的情况下缩小 ScrollView 中的表格
- git - 有没有办法删除子模块中的合并分支
- angular - 如何计算角度formarray和formcontrol中的总价
- python - 无法使用 ZipFile 打开子目录中的文件
- html - 是否可以使用
- jquery - HTML:如何显示格式日期“yyyy/mm/dd hh:mm”
- php - 如何部分禁用 PHPCS 的 PSR-12 declare(strict_types=1) 检查?
- r - 创建绘图后手动调整 alpha?
- c# - C# Settings.settings 显示为 XML 而不是网格视图