簡體   English   中英

使用 PySpark 將許多小的 csv 文件(130,000 個,每個文件有 2 列)有效地組合成一個大框架

[英]Using PySpark to efficiently combine many small csv files (130,000 with 2 columns in each) into one large frame

這是我發布的早期問題的另一個后續問題如何使用 PySpark 將這些許多 csv 文件(大約 130,000 個)有效地合並到一個大型數據集中?

我有以下數據集https://fred.stlouisfed.org/categories/32263/downloaddata/INTRNTL_csv_2.zip

其中有一個文件列表(大約 130,000 個)。 在列出了子目錄的主目錄中,第一個單元格可能是 A/AAAAA,文件將位於 /data/A/AAAAA.csv

這些文件都具有相似的格式,第一列稱為 DATE,第二列是一個系列,都命名為 VALUE。 所以首先需要將VALUE列名重命名為每個csv文件中的文件名 其次,幀需要以 DATE 為主要索引彼此完全外部連接。 第三,我想保存文件並能夠加載和操作它。 該文件應該大約為 N 行(日期數)X 130,001。

我正在嘗試將所有文​​件完全外部連接到一個數據幀中,我之前嘗試過 Pandas,但在嘗試連接文件列表時內存不足,有人建議我嘗試使用 PySpark。

在上一篇文章中,我被告知我可以這樣做:

df = spark.read.csv("/kaggle/input/bf-csv-2/BF_csv_2/data/**/*.csv", "date DATE, value DOUBLE")

但是所有的列都被命名為 value 並且框架只是變成了兩列,第一列是 DATE,第二列是 VALUE,它加載得非常快,大約 38 秒和大約 380 萬個值由 2 列,所以我知道它沒有做完整的外連接,它會按行附加文件。

所以我嘗試了以下代碼:

import pandas as pd
import time
import os

from pyspark.sql import SparkSession

spark = SparkSession.builder.appName('spark-dataframe-demo').getOrCreate()
from pyspark.sql import *
from pyspark.sql.functions import col
from pyspark.sql import DataFrame
from pyspark.sql.types import *

filelist = pd.read_excel("/kaggle/input/list/BF_csv_2.xlsx") #list of filenames

firstname = min(filelist.File)
length = len(filelist.File)

dff = spark.read.csv(f"/kaggle/input/bf-csv-2/BF_csv_2/data/" + firstname, inferSchema = True, header = True).withColumnRenamed("VALUE",firstname) #read file and changes name of column to filename

for row in filelist.File.items():
    if row == firstname:
        continue

    print (row[1],length,end='', flush=True)
    df = spark.read.csv(f"/kaggle/input/bf-csv-2/BF_csv_2/data/" + row[1], inferSchema = True, header = True).withColumnRenamed("VALUE",row[1][:-4])
    #df = df.select(col("DATE").alias("DATE"),col("VALUE").alias(row[1][:-4]))

    dff = dff.join(df, ['DATE'], how='full')

    length -= 1

dff.write.save('/kaggle/working/whatever', format='parquet', mode='overwrite')

所以為了測試它,我嘗試在 3 列合並后加載 df.show() 函數,它非常快。 但是,當我嘗試大約 25 列時,大約需要 2 分鍾。 當我嘗試 500 列時,這幾乎是不可能的。

我不認為我做得對。 格式和一切都是正確的。 但為什么需要這么長時間? 如何正確使用 PySpark? 有沒有更好的庫來實現我的需要?

與其他軟件相比,Spark 沒有任何神奇之處。 spark的優勢在於並行處理。 大多數情況下,這意味着您可以使用多台機器來完成工作。 如果您在本地運行 spark,您可能會遇到與使用 pandas 時相同的問題。

話雖如此,可能有一種方法可以讓您使用 Spark 在本地運行它,因為它可以在某些條件下溢出到磁盤,並且不需要將所有內容都保存在內存中。

我不擅長 PySpark,但我采取的方法是:

  1. 像你一樣使用/kaggle/input/bf-csv-2/BF_csv_2/data/**/*.csv加載所有文件
  2. 使用from pyspark.sql.functions import input_file_name的函數from pyspark.sql.functions import input_file_name它允許您獲取DF每條記錄的路徑( df.select("date", "value", input_file_name().as("filename"))或類似的)
  3. 將路徑解析為我想要作為列的格式(例如提取文件名)
  4. 在這一步date, value, filename架構應該看起來像date, value, filename
  5. 使用相當於df.groupBy("date").pivot("filename").agg(first("value"))df.groupBy("date").pivot("filename").agg(first("value")) 注意:我使用first()是因為我認為您可能有 1 或 0 條記錄
  6. 還可以嘗試:將分區數設置為等於您獲得的日期數
  7. 如果要將輸出作為單個文件,請不要忘記在df.write之前repartition(1) 根據數據大小,此步驟可能會出現問題。 如果您打算繼續使用 Spark 進行工作,則不需要這樣做,因為您可以使用與步驟 1 ( /new_result_data/*.csv ) 中相同的方法加載數據

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM