web-dev-qa-db-fra.com

Comment créer une copie d'une trame de données dans pyspark?

J'ai une trame de données à partir de laquelle je dois créer une nouvelle trame de données avec un petit changement dans le schéma en effectuant l'opération suivante.

>>> X = spark.createDataFrame([[1,2], [3,4]], ['a', 'b'])
>>> schema_new = X.schema.add('id_col', LongType(), False)
>>> _X = X.rdd.zipWithIndex().map(lambda l: list(l[0]) + [l[1]]).toDF(schema_new)

Le problème est que dans l'opération ci-dessus, le schéma de X est modifié en place. Donc, quand j'imprime X.columns Je reçois

>>> X.columns
['a', 'b', 'id_col']

mais les valeurs dans X sont toujours les mêmes

>>> X.show()
+---+---+
|  a|  b|
+---+---+
|  1|  2|
|  3|  4|
+---+---+

Pour éviter de modifier le schéma de X, j'ai essayé de créer une copie de X de trois manières - en utilisant les méthodes copy et deepcopy à partir des copy module - en utilisant simplement _X = X

Les méthodes copy ont échoué et renvoyé un

RecursionError: maximum recursion depth exceeded

La méthode d'affectation ne fonctionne pas non plus

>>> _X = X
>>> id(_X) == id(X)
True

Étant donné que leurs id sont les mêmes, la création d'une trame de données en double n'aide pas vraiment ici et les opérations effectuées sur _X se reflète dans X.

Donc ma question est vraiment double

  • comment changer la place du schéma (c'est-à-dire sans apporter de modifications à X)?

  • et plus important encore, comment créer un doublon d'une trame de données pyspark?

Remarque:

Cette question fait suite à cette post

6
Clock Slave

Comme expliqué dans la réponse à l'autre question, vous pouvez faire une copie profonde de votre schéma initial. Nous pouvons ensuite modifier cette copie et l'utiliser pour initialiser le nouveau DataFrame_X:

import pyspark.sql.functions as F
from pyspark.sql.types import LongType
import copy

X = spark.createDataFrame([[1,2], [3,4]], ['a', 'b'])
_schema = copy.deepcopy(X.schema)
_schema.add('id_col', LongType(), False) # modified inplace
_X = X.rdd.zipWithIndex().map(lambda l: list(l[0]) + [l[1]]).toDF(_schema)

Voyons maintenant:

print('Schema of X: ' + str(X.schema))
print('Schema of _X: ' + str(_X.schema))

Sortie:

Schema of X: StructType(List(StructField(a,LongType,true),StructField(b,LongType,true)))
Schema of _X: StructType(List(StructField(a,LongType,true),
                  StructField(b,LongType,true),StructField(id_col,LongType,false)))

Notez que pour copier un DataFrame, vous pouvez simplement utiliser _X = X. Chaque fois que vous ajoutez une nouvelle colonne avec par exemple withColumn, l'objet n'est pas modifié en place, mais une nouvelle copie est retournée. J'espère que cela t'aides!

3
Florian

À Scala:

  1. Avec "X.schema.copy", nouvelle instance de schéma créée sans ancienne modification de schéma;
  2. Dans chaque opération Dataframe, qui renvoie Dataframe ("sélectionner", "où", etc.), un nouveau Dataframe est créé, sans modification de l'original. L'original peut être utilisé encore et encore. Je suppose que la duplication n'est pas requise pour votre cas. Les performances sont un problème distinct, "persister" peut être utilisé.
1
pasha701