如何快速将id重新映射到连续数字

时间:2016-09-06 19:14:20

标签: python pandas dataframe

我有一个大型csv文件,其中的行看起来像

0,1
1,2
3,0

我需要对其进行转换,以便从0开始连续编号。在这种情况下,以下内容可以正常工作

import csv
names = {}
counter = 0
with open('foo.csv', 'rb') as csvfile:
     reader = csv.reader(csvfile)
     for row in reader:
         if row[0] in names:
             id1 =  row[0]
         else:
             names[row[0]] = counter
             id1 = counter
             counter += 1
         if row[1] in names:
             id2 = row[1]
         else:
             names[row[1]] = counter
             id2 = counter
             counter += 1
     print id1, id2

我目前的代码如下:

startAP

Python dicts遗憾地使用了大量内存,而且我的输入很大。

  

当输入太大而dict不适合内存时,我该怎么办

如果有更好/更快的方法来解决这个问题,我也会感兴趣。

3 个答案:

答案 0 :(得分:6)

df = pd.DataFrame([['a', 'b'], ['b', 'c'], ['d', 'a']])

v = df.stack().unique()
v.sort()
f = pd.factorize(v)
m = pd.Series(f[0], f[1])

df.stack().map(m).unstack()

enter image description here

答案 1 :(得分:3)

更新:这是一个内存保存解决方案,可将您的所有字符串转换为数字类别:

In [13]: df
Out[13]:
        c1       c2
0  stringa  stringb
1  stringb  stringc
2  stringd  stringa
3  stringa  stringb
4  stringb  stringc
5  stringd  stringa
6  stringa  stringb
7  stringb  stringc
8  stringd  stringa

In [14]: x = (df.stack()
   ....:        .astype('category')
   ....:        .cat.rename_categories(np.arange(len(df.stack().unique())))
   ....:        .unstack())

In [15]: x
Out[15]:
  c1 c2
0  0  1
1  1  2
2  3  0
3  0  1
4  1  2
5  3  0
6  0  1
7  1  2
8  3  0

In [16]: x.dtypes
Out[16]:
c1    category
c2    category
dtype: object

OLD回答:

我认为您可以对列进行分类:

In [63]: big.head(15)
Out[63]:
         c1       c2
0   stringa  stringb
1   stringb  stringc
2   stringd  stringa
3   stringa  stringb
4   stringb  stringc
5   stringd  stringa
6   stringa  stringb
7   stringb  stringc
8   stringd  stringa
9   stringa  stringb
10  stringb  stringc
11  stringd  stringa
12  stringa  stringb
13  stringb  stringc
14  stringd  stringa

In [64]: big.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 30000000 entries, 0 to 29999999
Data columns (total 2 columns):
c1    object
c2    object
dtypes: object(2)
memory usage: 457.8+ MB

所以big DF有30M行,它的大小是大约。 460MiB ...

让我们对它进行分类:

In [65]: cat = big.apply(lambda x: x.astype('category'))

In [66]: cat.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 30000000 entries, 0 to 29999999
Data columns (total 2 columns):
c1    category
c2    category
dtypes: category(2)
memory usage: 57.2 MB

现在只需57MiB,看起来完全一样:

In [69]: cat.head(15)
Out[69]:
         c1       c2
0   stringa  stringb
1   stringb  stringc
2   stringd  stringa
3   stringa  stringb
4   stringb  stringc
5   stringd  stringa
6   stringa  stringb
7   stringb  stringc
8   stringd  stringa
9   stringa  stringb
10  stringb  stringc
11  stringd  stringa
12  stringa  stringb
13  stringb  stringc
14  stringd  stringa

让我们将它的大小与类似的数字DF进行比较:

In [67]: df = pd.DataFrame(np.random.randint(0,5,(30000000,2)), columns=list('ab'))

In [68]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 30000000 entries, 0 to 29999999
Data columns (total 2 columns):
a    int32
b    int32
dtypes: int32(2)
memory usage: 228.9 MB

答案 2 :(得分:3)

如果您需要一系列ID,请使用factorize

df = pd.read_csv(data, header=None, prefix='Col_')
print (pd.factorize(np.hstack(df.values)))

(array([0, 1, 1, 2, 3, 0]), array(['stringa', 'stringb', 'stringc', 'stringd'], dtype=object))

编辑:(根据评论)

您可以获取factorize方法后获得的元组切片,并相应地映射到整个dataframe,如下所示相互替换:

num, letter = pd.factorize(np.hstack(df.values))

df.replace(to_replace=sorted(list(set(letter))), value=sorted(list(set(num))))

   Col_0  Col_1
0      0      1
1      1      2
2      3      0