如何从大型 csv 文件 return 一个具有预期形状的 numpy 数组?

How to return a numpy arrays with expected shape from large csv file?

我期望的 return 数组 S1 的形状是 (20,10)。为什么是 (22,10)? (2)如何从df0和df1中提取一些行并有效地构造一个新数组?

csv文件不大,但可以超过8G,参数M可以大于2000

我的代码如下

import dask.dataframe as dd
import numpy as np
from tensorflow.keras.utils import to_categorical

# Define df's
file0 = './dataset_zeros.csv'
file1 = './dataset_ones.csv'
df0 = dd.read_csv(file0,dtype="str",header=None)
df1 = dd.read_csv(file1,dtype="str",header=None)
#Drop the index
df0 = df0.drop(0,axis=1)
df1 = df1.drop(0,axis=1)

def generate_S(file0, file1,init,M,N_in,N_out):
    a = int(M/N_out) # if M=20, N_out=2, then a=10
    #Read csv files
    df0 = dd.read_csv(file0,header=None)
    df1 = dd.read_csv(file1,header=None)
    # Drop the index
    df0 = df0.drop(0,axis=1)
    df1 = df1.drop(0,axis=1)
    
    start = init*a
    end = (init+1)*a

    # extract a=10 rows from df0 (Part 1)
    train_X0 = df0.loc[start:end,:] # select rows
    train_X0 = train_X0.iloc[:,:10] # select columns
    train_X0 = train_X0.values # Convert dataframe to array
    
    # extract a=10 rows from df1 (Part 1)
    train_X1 = df1.loc[start:end]
    train_X1 = train_X1.iloc[:,:10]
    train_X1 = train_X1.values
    

    # concatenate the two parts to a new array
    new_X = np.concatenate((train_X0, train_X1), axis=0)
    
    #================================
    #res = new_X.reshape(M,N_in)
    res= new_X
    return res

# Examples of Parameters
init = 2
M = 20
N_in = 10
N_out =2

# Call the function
S1= generate_S(file0,file1,init,M,N_in,N_out)

数据帧 df0 和 df1 看起来像

那我运行

S1.compute_chunk_sizes()

结果是

“我预期的 return 数组 S1 的形状是 (20,10)。为什么是 (22,10)?”这是因为我没有看懂索引startend:在df.loc[]中,startend都被考虑在内了!比如我要提取10行,我应该设置start=20; end=29,而不是start=20; end=30.

正确的代码是:

start = init*a
end = (init+1)*a - 1
# extract a=10 rows from df0 (Part 1)
train_X0 = df0.loc[start:end,:] # select rows

因此函数generate_S()修改如下

def generate_S(file0, file1,init,M,N_in,N_out):
    a = int(M/N_out)
    #Read csv files
    df0 = dd.read_csv(file0,header=None)
    df1 = dd.read_csv(file1,header=None)
    # Drop the index
    df0 = df0.drop(0,axis=1)
    df1 = df1.drop(0,axis=1)
    
    start = init*a
    end = (init+1)*a - 1
    
    # extract a=10 rows from df0 (Part 1)
    train_X0 = df0.loc[start:end,:] # select rows
    train_X0 = train_X0.iloc[:,:10] # select columns
    train_X0 = train_X0.values # Convert dataframe to array
    
    # extract a=10 rows from df1 (Part 1)
    train_X1 = df1.loc[start:end]
    train_X1 = train_X1.iloc[:,:10]
    train_X1 = train_X1.values
    
    new_X = np.concatenate((train_X0, train_X1), axis=0)
    new_X.compute_chunk_sizes()
    
    #Test
    print("new_X.SHAPE:")
    print(new_X.shape)
    
    res = new_X.reshape(M,N_in)
    return res

该函数将 return 一个形状为 (M, 10) 的数组(在此代码中,M=20)。问题的第 1 部分已解决。

问题的第 2 部分是:当 csv 文件很大时,函数 generate_S() 中的 new_X.compute_chunk_sizes() 非常耗时。更糟糕的是,它给出了错误的结果。对于我的大型 csv 文件,new_X 的形状是:

new_X.SHAPE:
(1170, 784)

但预期的是 (a, 784)。这里,a=10。看来函数 generate_S() 是对每个块进行操作的! (这个例子中有117个chunk。)我真的很想它只运行一次。

希望能找到一个正确高效的方法来实现这个功能

=====

我找到了正确的方法。 dask 在这里不是必需的。要从大型 csv 文件生成数组,我可以在 pandas.read_csv() 中使用关键字 skiprowsnrows。这是我的新版本的功能。它从两个 csv 文件中读取行并将它们合并到一个数组中。

import pandas as pd

def generate_S(file0, file1,init,M,N_in,N_out):
    a = int(M/N_out)
    #Read csv files
    df0 = pd.read_csv(file0,header=None,skiprows=(init-1)*a, nrows=a)
    df1 = pd.read_csv(file1,header=None,skiprows=(init-1)*a, nrows=a)
    # Drop the index
    df0 = df0.drop(0,axis=1)
    df1 = df1.drop(0,axis=1)
    #0
    train_X0 = df0.iloc[:,:-1] # select columns
    train_X0 = train_X0.values # Convert dataframe to array  
    #1
    train_X1 = df1.iloc[:,:-1]
    train_X1 = train_X1.values
    
    new_X = np.concatenate((train_X0, train_X1), axis=0)
    return new_X

问题已解决