选择每第 n 行作为 Pandas DataFrame 而无需读取整个文件

Posted

技术标签:

【中文标题】选择每第 n 行作为 Pandas DataFrame 而无需读取整个文件【英文标题】:Select every nth row as a Pandas DataFrame without reading the entire file 【发布时间】:2019-05-17 15:14:47 【问题描述】:

我正在读取一个包含约 950 万行 x 16 列的大文件。

我对检索有代表性的样本感兴趣,并且由于数据是按时间组织的,因此我想通过选择每 500 个元素来做到这一点。

我能够加载数据,然后每 500 行选择一次。

我的问题:我可以立即读取每 500 个元素(使用.pd.read_csv() 或其他方法),而不必先读取然后过滤我的数据吗?

问题 2:如果没有对日期列进行排序,您将如何解决这个问题?目前,我假设它是按日期排序的,但所有数据都容易出错。

这是数据的样子(前 5 行)的 sn-p

VendorID    tpep_pickup_datetime    tpep_dropoff_datetime   passenger_count trip_distance   RatecodeID  store_and_fwd_flag  PULocationID    DOLocationID    payment_type    fare_amount extra   mta_tax tip_amount  tolls_amount    improvement_surcharge   total_amount
0   1   2017-01-09 11:13:28 2017-01-09 11:25:45 1   3.30    1   N   263 161 1   12.5    0.0 0.5 2.00    0.00    0.3 15.30
1   1   2017-01-09 11:32:27 2017-01-09 11:36:01 1   0.90    1   N   186 234 1   5.0 0.0 0.5 1.45    0.00    0.3 7.25
2   1   2017-01-09 11:38:20 2017-01-09 11:42:05 1   1.10    1   N   164 161 1   5.5 0.0 0.5 1.00    0.00    0.3 7.30
3   1   2017-01-09 11:52:13 2017-01-09 11:57:36 1   1.10    1   N   236 75  1   6.0 0.0 0.5 1.70    0.00    0.3 8.50
4   2   2017-01-01 00:00:00 2017-01-01 00:00:00 1   0.02    2   N   249 234 2   52.0    0.0 0.5 0.00    0.00    0.3 52.80

【问题讨论】:

第一个问题,相信read_csv的skiprows参数会派上用场 【参考方案1】:

我是否可以立即读取每 500 个元素(使用.pd.read_csv() 或其他方法),而不必先读取然后过滤我的数据?

您可以做的是使用read_csv 中的skiprows 参数,它接受一个类似列表的参数来丢弃感兴趣的行(因此也选择)。所以你可以创建一个长度等于要读取的行数的np.arange,并使用np.delete从中删除每个500th元素,所以这样我们只会每500行读取一次:

n_rows = 9.5e6
skip = np.arange(n_rows)
skip = np.delete(skip, np.arange(0, n_rows, 500))
df = pd.read_csv('my_file.csv', skiprows = skip)

【讨论】:

非常有用。要将记录量减少不到一半,删除步骤可能会发生多次 np.delete() 在我尝试执行代码时产生错误:IndexError: arrays used as indices must be of integer (or boolean) type【参考方案2】:

我是否可以立即读取每 500 个元素(使用.pd.read_csv() 或其他方法),而不必先读取然后过滤我的数据?

首先通过自定义函数获取文件的长度,通过numpy.setdiff1d删除每500行并传递给read_csv中的skiprows参数:

#https://***.com/q/845058
def file_len(fname):
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

len_of_file = file_len('test.csv')
print (len_of_file)

skipped = np.setdiff1d(np.arange(len_of_file), np.arange(0,len_of_file,500))
print (skipped)

df = pd.read_csv('test.csv', skiprows=skipped)

如果没有对日期列进行排序,您将如何解决这个问题?目前,我假设它是按日期排序的,但所有数据都容易出错。

思路是通过参数usecols只读datetime列,然后对每500个索引值进行排序选择,得到差值再传给参数skiprows

def file_len(fname):
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

len_of_file = file_len('test.csv')

df1 = pd.read_csv('test.csv',
                  usecols=['tpep_pickup_datetime'],
                  parse_dates=['tpep_pickup_datetime'])

sorted_idx = (df1['tpep_pickup_datetime'].sort_values()
                 .iloc[np.arange(0,len_of_file,500)].index)

skipped = np.setdiff1d(np.arange(len_of_file), sorted_idx)
print (skipped)

df = pd.read_csv('test.csv', skiprows=skipped).sort_values(by=['tpep_pickup_datetime'])

【讨论】:

以上是关于选择每第 n 行作为 Pandas DataFrame 而无需读取整个文件的主要内容,如果未能解决你的问题,请参考以下文章

从字符串中选择每第 n 个字符

XSLT 将每第 n 个项目分组到新组中

如何在 SQL (postgresql) 中选择每第 n 分钟的行

从 OpenCV 中的 VideoCapture 中读取每第 n 帧

react.js每第n个项目添加开始标签或结束标签

每第 N 个单词插入字符串