基本CSV文件的

时间:2015-08-02 19:35:27

标签: python dictionary optimization pandas dataframe

我有一个伪CSV文件(用管道分隔);有两列,第一列标题是位置,与问题无关。两列中的第二列是标识符(在本例中为用户名)。该文件看起来像这样

Location | Username 
San Francisco, CA | sam001040
Chicago, IL | tinytom
New York City, NY | coder23
Palo Alto, CA | sam001040

你可以注意到,sam001040,我在两个城市(旧金山和帕洛阿尔托)看到了。

我需要为用户名分配一个唯一的标识号,并使用新的ID号创建一个新的类似格式的表。映射(用户名 - > id)应存储到磁盘。应该存储映射,因为如果在几天内我可能需要处理另一个文件,那么我可以重用以前存储的映射。

因此在id进程之后文件看起来应该是

Location | Username | UniqueID
San Francisco, CA | sam001040 | 0
Chicago, IL | tinytom | 1
New York City, NY | coder23 | 2
Palo Alto, CA | sam001040 | 0

几天后,这样的文件可以进入

Location | Username 
Grand Rapids, MI | gowolves
Chicago, IL | ill
Los Angeles, CA | trojans 
Castro Valley, CA | coder23

由于有一些新的用户名,因此需要创建新的标识符,并从上次看到。所以输出的新文件应该是这样的

Location | Username | UniqueID
Grand Rapids, MI | gowolves | 3
Chicago, IL | illini | 4
Los Angeles, CA | trojans | 5
Castro Valley, CA | coder23 | 2

这是一个link to the code,有一些评论,希望名称有用,但我可以澄清一切。

一些警告

  1. 我操作的文件是1.3gb,大约20,000,000行,用户名重复约30%(翻译成字典中的14,000,000个键)
  2. 目前只能访问我的本地计算机(MBP,8 GB内存,512闪存)
  3. 其他信息/到目前为止我尝试了什么

    • 最初我在python中使用了循环,然后意识到这不是好习惯,相应地切换到pandas数据帧并使用lambdas
    • 写入另一个文件,然后决定打印到控制台并重定向到另一个文件(使用>)
    • 试图整个处理文件,这总是导致一些东西中断,一旦耗尽了500 GB的内存(不知道是怎么回事)。
    • 将大型1.3 gb文件分解为50个较小的文件,每个文件需要约3个小时才能处理
    • 之前尝试过酸洗,然后在阅读Pickle vs. Json之后切换到json存储字典(评论中的链接)
    • 我跑了一个探查器(SnakeViz)和here are the results。根据我的理解,似乎检查字典中的键是占用时间,但是从我的理解中读取另一个stackoverflow帖子“in”通常最快(Most efficient method to check if dictionary key exists and process its value if it does

    主要问题 -

    我做错了吗?我整整一周都在看这个,不知道还有什么可做的。我认为处理所有事情的时间不会超过150小时。

    如果有人有任何建议或想法,请告诉我!这是我的第一篇文章,所以如果我需要包含更多信息(或删除一些信息),我会提前道歉,并会相应地调整帖子。

2 个答案:

答案 0 :(得分:0)

一般情况下,检查某个键是否在字典中时,请执行k in d,而不是k in d.items(),这会非常慢,例如

In [68]: d = {x:x+1 for x in range(100000)}

In [69]: %timeit (67 in d)
10000000 loops, best of 3: 39.2 ns per loop

In [70]: %timeit (67 in d.items())
100 loops, best of 3: 10.8 ms per loop

仅此一点就会产生很大的影响。但是,我会使用更像这样的模式,这样可以加快速度。 .map查找现有用户的ID,.unique()获取一组新用户名(过滤到查找表中未匹配的用户名)。

df['UserId'] = df['Username'].map(segment_dict)

new_users = df[pd.isnull(df['UserId'])]['Username'].unique()
for u in new_users:
    segment_dict[u] = unique_ids
    unique_ids += 1

答案 1 :(得分:0)

您可以尝试将User -> ID映射保留为CSV格式,以便在pandas中使用。

假设您有一个CSV文件,将已知用户名映射到ID:

$  cat ids.csv
sam001040,0
tinytom,1
coder23,2

您需要处理的新文件newfile.txt

$  cat newfile.txt
Location | Username
Grand Rapids, MI | gowolves
Chicago, IL | ill
Los Angeles, CA | trojans
Castro Valley, CA | coder23

您在ids.csv读到了

ids = pd.read_csv('ids.csv', header=None, index_col=0, names=['Username', 'ID'])

newfile.txt

newfile = pd.read_csv('newfile.txt', sep=' \| ', skipinitialspace=True)
# or pd.read_csv('newfile.txt', sep='|'), which is faster, but won't work nice
# when the file has spaces like you show

现在你可以做到:

newfile_with_ids = newfile.merge(ids, left_on='Username', right_index=True, how='left')

已填写所有已知ID:

            Location  Username  ID
0   Grand Rapids, MI  gowolves NaN
1        Chicago, IL       ill NaN
2    Los Angeles, CA   trojans NaN
3  Castro Valley, CA   coder23   2

现在,添加新ID:

mask = newfile_with_ids['ID'].isnull()
ids = pd.concat([ids, pd.DataFrame(
         data={'ID': 1 + int(ids.iloc[-1]) + np.arange(mask.sum())},
         index=newfile_with_ids.loc[mask, 'Username'].drop_duplicates())])

得到:

           ID
Username     
sam001040   0
tinytom     1
coder23     2
gowolves    3
ill         4
trojans     5

然后将新ID写入数据帧:

newfile_with_ids.loc[mask, 'ID'] = ids.loc[
         newfile_with_ids.loc[mask, 'Username'], 'ID'].values

最后你有:

            Location  Username  ID
3  Castro Valley, CA   coder23   2
0   Grand Rapids, MI  gowolves   3
1        Chicago, IL       ill   4
2    Los Angeles, CA   trojans   5

最后,保存新的ids并继续。