以 Pandas DataFrame 的形式选择每第 n 行,而不需要读取整个文件

8

我正在阅读一个包含约9.5百万行x 16列的大文件。

我希望检索一个代表性样本,并且由于数据按时间组织,所以我想通过选择每500个元素来实现这一点。

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

我的问题是:我能否立即读取每500个元素(使用.pd.read_csv()或其他方法),而无需先读取数据,然后再进行筛选?

问题2:如果日期列未排序,您将如何解决此问题?目前,我假设它按日期排序,但所有数据都容易出错。

以下是数据的一部分示例(前五行)。前4行是无序的,但剩余的数据集看起来是有序的(按时间排序):

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参数会很方便。 - grshankar
pd.read_csv(..., skiprows=lambda i: i % n) - william_grisaitis
4个回答

10
我能立即读取每500个元素吗(使用.pd.read_csv()或其他方法),而不必先读取数据然后再筛选数据吗?你可以在read_csv中使用skiprows参数,该参数接受一个类似列表的参数以丢弃我们感兴趣的行(因此也进行选择)。因此,您可以创建一个长度等于要读取的行数的np.arange,并使用np.delete从中删除每500个元素,这样我们只会读取每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)

非常有用。为了将记录数量减少不到一半,删除步骤可能需要多次执行。 - mik
当我尝试执行代码时,np.delete() 生成了一个错误:IndexError: 用作索引的数组必须是整数(或布尔)类型。 - stevehs17

3
我能立即读取每500个元素吗(使用.pd.read_csv()或其他方法),而无需先读取数据然后再过滤数据吗?
首先,通过自定义函数获取文件的长度,使用numpy.setdiff1d逐行删除每个500行,并将其传递给read_csv中的skiprows参数:
#https://dev59.com/X3RA5IYBdhLWcg3wvQlh
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'])

2

0

您可以使用 csv 模块返回一个迭代器,并使用 itertools.cycle 选择每个第 n 行。

import csv
from itertools import cycle

source_file='D:/a.txt'
cycle_size=500
chooser = (x == 0 for x in cycle(range(cycle_size))) 
with open(source_file) as f1:
    rdr = csv.reader(f1) 
    data = [row for pick, row in zip(chooser, rdr) if pick]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接