从两个csv文件python中选择记录

时间:2017-11-15 19:49:21

标签: python pandas csv

我有两个csv文件。 train_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条唯一记录。这就是为什么我用pandas排序独特的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个user_log记录。我的代码在大约20分钟后停止,在results.csv中只有104条记录 - 所需的输出文件匹配msno - user_logs。

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

1 个答案:

答案 0 :(得分:0)

可能的原因导致它在没有找到所有内容的情况下停止:

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

你可以通过在内部循环完成后(无论是通过StopIteration还是中断)将文件发送回开头来修复,以便内部循环可以搜索整个文件以查找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-ish迭代。你必须小心嵌套循环。

当你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)
        ....

它不会减少迭代次数,但如果你得到(a_small_improvement * 9e8)改进,那么它可能会很明显。

看起来你正在制作一个DataFrame然后扔掉它。直接从文件中生成unique_msnos可能更快:

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

您需要尝试检查它是否更快。

当您尝试使其工作并进行优化时,您可能希望自己制作一些较小的文件。只需为每个文件执行一次,然后使用小文件进行debuging。使用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