web-dev-qa-db-fra.com

Comment découper une trame de données Pyspark en deux lignes

Je travaille à Databricks.

J'ai une trame de données qui contient 500 lignes, je voudrais créer deux trames de données contenant 100 lignes et l'autre contenant les 400 lignes restantes.

+--------------------+----------+
|              userid| eventdate|
+--------------------+----------+
|00518b128fc9459d9...|2017-10-09|
|00976c0b7f2c4c2ca...|2017-12-16|
|00a60fb81aa74f35a...|2017-12-04|
|00f9f7234e2c4bf78...|2017-05-09|
|0146fe6ad7a243c3b...|2017-11-21|
|016567f169c145ddb...|2017-10-16|
|01ccd278777946cb8...|2017-07-05|

J'ai essayé ce qui suit mais je reçois une erreur

df1 = df[:99]
df2 = df[100:499]


TypeError: unexpected item type: <type 'slice'>
8
Data_101

Au début, j'ai mal compris et j'ai pensé que vous vouliez couper les colonnes. Si vous souhaitez sélectionner un sous-ensemble de lignes, une méthode consiste à créer une colonne d'index à l'aide de monotonically_increasing_id() . De la documentation:

L'ID généré est garanti d'être monotone croissant et unique, mais pas consécutif.

Vous pouvez utiliser cet ID pour trier la trame de données et la sous-définir à l'aide de limit() pour vous assurer d'obtenir exactement les lignes souhaitées.

Par exemple:

import pyspark.sql.functions as f
import string

# create a dummy df with 500 rows and 2 columns
N = 500
numbers = [i%26 for i in range(N)]
letters = [string.ascii_uppercase[n] for n in numbers]

df = sqlCtx.createDataFrame(
    Zip(numbers, letters),
    ('numbers', 'letters')
)

# add an index column
df = df.withColumn('index', f.monotonically_increasing_id())

# sort ascending and take first 100 rows for df1
df1 = df.sort('index').limit(100)

# sort descending and take 400 rows for df2
df2 = df.sort('index', ascending=False).limit(400)

Juste pour vérifier que cela a fait ce que vous vouliez:

df1.count()
#100
df2.count()
#400

Nous pouvons également vérifier que la colonne d'index ne se chevauche pas:

df1.select(f.min('index').alias('min'), f.max('index').alias('max')).show()
#+---+---+
#|min|max|
#+---+---+
#|  0| 99|
#+---+---+

df2.select(f.min('index').alias('min'), f.max('index').alias('max')).show()
#+---+----------+
#|min|       max|
#+---+----------+
#|100|8589934841|
#+---+----------+
8
pault

Les trames de données Spark ne peuvent pas être indexées comme vous écrivez. Vous pouvez utiliser la méthode head pour créer pour prendre les n premières lignes. Cela renverra une liste d'objets Row () et non une trame de données. Vous pouvez donc les reconvertir en trame de données et utiliser la soustraction de la trame de données d'origine pour prendre le reste des lignes.

#Take the 100 top rows convert them to dataframe 
#Also you need to provide the schema also to avoid errors
df1 = sqlContext.createDataFrame(df.head(100), df.schema)

#Take the rest of the rows
df2 = df.subtract(df1)

Vous pouvez également utiliser SparkSession au lieu de spark sqlContext si vous travaillez sur spark 2.0+. Également si vous n'êtes pas intéressé à prendre les 100 premières lignes et que vous voulez une répartition aléatoire que vous pouvez utiliser randomSplit comme ceci:

df1,df2 = df.randomSplit([0.20, 0.80],seed=1234)
7
Michail N

Si cela ne me dérange pas d'avoir les mêmes lignes dans les deux trames de données, je peux utiliser sample. Par exemple J'ai un dataframe avec 354 lignes.

>>> df.count()
354

>>> df.sample(False,0.5,0).count() //approx. 50%
179

>>> df.sample(False,0.1,0).count() //approx. 10%
34

Alternativement, si je veux séparer strictement sans que des doublons soient présents, je pourrais faire

df1 = df.limit(100)     //100 rows
df2 = df.subtract(df1)  //Remaining rows
2
Bala