2016-09-06 20 views
6

Ben bu durumda bu nedenle kimlikleri ardışık 0'dan numaralandırılmıştır dönüştürmek gerekir ardışık sayılara kimlikleri yeniden eşleştirmek için ne kadar çabuk

stringa,stringb 
stringb,stringc 
stringd,stringa 

benziyor hatları ile büyük bir csv dosyası var çalışacak aşağıdaki Python dicts ne yazık ki çok fazla bellek kullanmak

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 

: gibi

0,1 
1,2 
3,0 

Bulunduğum kod görünüyor ve girdim büyük. dict belleğine

genel olarak bu sorunu çözmek için daha iyi/hızlı bir yolu var olup olmadığını da ilgi olacağını sığacak şekilde alanındaki giriş çok büyük olduğunda

ne yapabilirim. GÜNCELLEME

+0

Bir sözlük/karma haritası kullanma genel stratejisi doğrudur, ancak biraz garip davranıyorsunuz. Girişinizin belleğe sığmayacak kadar büyük olduğunu söylediğinizde, burada ne konuşuyoruz? Bazı arama tabloları (dict) veya diğer yetkili referanslar olmadan, benzersizliği veya ardışıklığı garanti edemezsiniz. –

+0

@NathanielFord Başlamak için daha az garip bir yolu bilmek isterim. – eleanora

+0

Ardından, derhal verdiğiniz örnekte verdiğiniz çıktıdan 0,1,2,3 vb. –

cevap

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

Bu akıllı ve çok temiz bir çözüm! – MaxU

+1

Teşekkür ederiz @MaxU – piRSquared

+2

Ayrıca bellek tasarrufu için kategorize etmeyi denerim ... – MaxU

2

:

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 

ESKİ cevap::

Ben Sütunlarınızı kategorize düşünüyorum:

burada sayısal kategorilerin için tüm dize dönüştüren bir bellek tasarrufu çözümdür
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 

DF 30M satırları vardır ve boyutu i yaklaşık 460MiB ...

Şunu kategorize edelim:

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 

Artık sadece 57MiB alır ve tamamen aynı görünüyor:

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 
:

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 

en karşılaştıralım benzer sayısal DF ile boyut var

+0

Bu kod yeni sayısal kimliklerle birlikte verilebilir mi? – eleanora

+0

Demek istediğim, girdinin girdi ile aynı biçimde olması ancak ids ile yeniden adlandırılması gerekiyor. – eleanora

+0

@eleanora, lütfen piRSquared'un çözümünü kontrol edin - size IDS verecesi verir – MaxU

3

Bir dizi kimlik istiyorsanız factorize'u kullanabilirsiniz:

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)) 

DÜZENLEME:

(yorum göre) Bu factorize yöntem sonra elde edilen başlığın dilimlerini sürebilir ve gösterildiği gibi birbirini yerine tüm dataframe buna göre harita:

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 
+0

Çıktının, yalnızca kimlikleri yeniden adlandırılan girdiyle aynı biçimde olması gerekiyor. – eleanora