从两个csv文件中选择记录

2024-04-23 22:04:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个csv文件。列车\u all.csv:

    msno                                         is_churn
0   waLDQMmcOu2jLDaV1ddDkgCrB/jl6sD66Xzs0Vqax1Y=    1
1   QA7uiXy8vIbUSPOkCf9RwQ3FsT8jVq2OxDr8zqa7bRQ=    1
2   fGwBva6hikQmTJzrbz/2Ezjm5Cth5jZUNvXigKK2AFA=    1
3   mT5V8rEpa+8wuqi6x0DoVd3H5icMKkE9Prt49UlmK+4=    1
4   XaPhtGLk/5UvvOYHcONTwsnH97P4eGECeq+BARGItRw=    1
5   GBy8qSz16X5iYWD+3CMxv/Hm6OPSrXBYtmbnlRtknW0=    1
6   lYLh7TdkWpIoQs3i3o6mIjLH8/IEgMWP9r7OpsLX0Vo=    1

它有1963891条记录,但只有1082190条独特的记录。这就是为什么我用熊猫来分类独特的msno-s。 另一个csv大约为30GB,包含9亿多条用户日志记录

msno    date    num_25  num_50  num_75  num_985 num_100 num_unq total_secs
rxIP2f2aN0rYNp+toI0Obt/N/FYQX8hcO1fTmmy2h34=    20150513    0   0   0   0   1   1   280.335
rxIP2f2aN0rYNp+toI0Obt/N/FYQX8hcO1fTmmy2h34=    20150709    9   1   0   0   7   11  1658.948
yxiEWwE9VR5utpUecLxVdQ5B7NysUPfrNtGINaM2zA8=    20150105    3   3   0   0   68  36  17364.956
yxiEWwE9VR5utpUecLxVdQ5B7NysUPfrNtGINaM2zA8=    20150306    1   0   1   1   97  27  24667.317
yxiEWwE9VR5utpUecLxVdQ5B7NysUPfrNtGINaM2zA8=    20150501    3   0   0   0   38  38  9649.029

我想遍历train_all.csv中唯一的msno-s,并在user_logs.csv中为每个msno搜索5个用户日志记录。我的代码在大约20分钟后停止,在results.csv中只有104条记录-需要的输出文件中有匹配的msno-user\u日志

import pandas as pd
import csv

reader = csv.reader(open('user_logs/user_logs.csv','r'))
writer = csv.writer(open('results.csv','w',newline=''))

data = pd.read_csv("train_all.csv")
unique_msnos = data["msno"].unique()

i = 0

for msno in range(len(unique_msnos)):
    counter = 0

    for row in reader:
        results_row = row

        if unique_msnos[msno] == row[0]:
            writer.writerow(results_row)
            counter+=1
            if counter == 5:
                i+=1
                break
            else:
                continue
        else:
            continue

Tags: csv记录counterallresultsnumreaderwriter
1条回答
网友
1楼 · 发布于 2024-04-23 22:04:44

可能的原因是它没有找到所有东西就停止了:

  • 每次读取一行时,内部循环都会推进文件中的位置
  • 当您跳出内部循环时,文件计数器/指针/位置(?)将保持在它离开的位置
  • 在外循环的下一次迭代中,内循环从最后一个文件位置开始,而不是从开始。因此在文件的前几行中找不到任何有效的msno。您可以通过在内部循环之前打印文件的位置(file.tell())来验证这一点(记住ctrl-c可以中断它)

您可以通过在内部循环完成后将文件发送回开头(无论是StopIteration还是break)来解决这个问题,这样内部循环就可以在整个文件中搜索msno。准备等待更长的时间

with open('user_logs/user_logs.csv','r') as infile:
    reader = csv.reader(infile)
    for msno in range(len(unique_msnos)):
        counter = 0
        #print(infile.tell())
        for row in reader:
            #inner_loop_stuff...
            #inner_loop_stuff...
            #inner_loop_stuff...
        infile.seek(0)

unique_msnos有1.1E6条记录,reader有9E8条记录。对于unique_msnos中的每条记录,您将迭代9e8次,这将是1e15次迭代。必须小心嵌套循环

checking for membership你应该使用一个集合

unique_msnos = set(unique_msnos)

您希望跟踪找到的记录数,因此可以使用unique_msnos值创建一个字典来保存计数

unique_msnos = dict.fromkeys(unique_msnos, 0)

然后迭代reader检查成员身份并添加逻辑,看看是否已经有5个:

for row in reader:
    c = unique_msnos.get(row[0], None)
    if c in (5, None):
        continue
    writer.write(row)
    unique_msnos[row[0]] += 1
    ...

这应该会在一定程度上减轻-9e8迭代。可能还有其他优化


如果msno-s都保证相同的长度,您可以使用切片而不是使用csv.Reader获得增量改进。我真的不知道csv阅读器有多快,但是切片速度非常快

像这样的

# unique_msnos is a dictionary
with open(open('user_logs/user_logs.csv','r') as f:
    for line in f:
        c = unique_msnos.get(line[:44], None)
        ....

它不会减少迭代次数,但是如果你得到(一个小的改进*9e8)的改进,它可能是显而易见的


看起来您正在创建一个数据帧,然后将其丢弃。直接从文件生成unique_msnos可能更快:

unique_msnos = {}
with open("train_all.csv") as f:
    for line in f:
        _, msno, churn = line.split()
        unique_msnos[msno] = 0

你需要试试看速度是否更快


当您试图让它工作并进行优化时,您可能希望为自己创建一些较小的文件。只需为每个文件执行一次,然后使用小文件进行调试。使用cprofiletimeit尝试找出瓶颈所在

limit = 10000  # or whatever
with open(file_path, 'r') as infile, open(small_filepath, 'w') as outfile:
    for n, line in enumerate(infile):
        outfile.write(line)
        if n == limit:
            break

相关问题 更多 >