2015-07-22 4 views
4

У меня довольно большой размер данных pandas (1.5gig .csv на диске). Я могу загрузить его в память и запросить его. Я хочу, чтобы создать новый столбец, комбинированное значение двух других столбцов, и я попытался это:Как справиться с изменением больших кадров данных pandas

def combined(row): 
    row['combined'] = row['col1'].join(str(row['col2'])) 
return row 

df = df.apply(combined, axis=1) 

В результате моего процесс питона был убит, предположительно, из-за проблемы с памятью.

Более итеративный решение проблемы, кажется:

df['combined'] = '' 
col_pos = list(df.columns).index('combined') 
crs_pos = list(df.columns).index('col1') 
sub_pos = list(df.columns).index('col2') 

for row_pos in range(0, len(df) - 1): 
    df.iloc[row_pos, col_pos] = df.iloc[row_pos, sub_pos].join(str(df.iloc[row_pos, crs_pos])) 

Это, конечно, кажется, очень unpandas. И очень медленно.

В идеале мне бы хотелось что-то вроде apply_chunk(), которое аналогично применять, но работает только на части фрейма. Я думал, что dask может быть вариантом для этого, но dask DataFrames, похоже, имели другие проблемы, когда я их использовал. Это должно быть общей проблемой, хотя, есть ли шаблон проектирования, который я должен использовать для добавления столбцов в большие кадры данных панд?

+1

Прежде всего, 'dask' не поможет в вашем случае, потому что ваша проблема связана с I/O и памятью вместо привязки к процессору, а' dask' основан на модуле «многопроцессорности». –

+0

Dask может использовать потоковые, многопроцессорные или распределенные вычисления. В его случае, хотя он не нуждается ни в одном из них, просто способ разумно обрабатывать потоковые данные с диска. – MRocklin

+0

Что касается использования метода apply? – PlagTag

ответ

4

Я хотел бы попробовать использовать список постижение + itertools:

df = pd.DataFrame({ 
    'a': ['ab'] * 200, 
    'b': ['ffff'] * 200 
}) 


import itertools 

[a.join(b) for (a, b) in itertools.izip(df.a, df.b)] 

Это может быть «unpandas», но панды, кажется, не имеют .str метод, который помогает вам здесь, и это не «unpythonic ».

Чтобы создать еще один столбец, просто используйте:

df['c'] = [a.join(b) for (a, b) in itertools.izip(df.a, df.b)] 

Кстати, вы также можете получить ваш комков с помощью:

[a.join(b) for (a, b) in itertools.izip(df.a[10: 20], df.b[10: 20])] 

Если вы хотите играть с распараллеливания. Сначала я попытался бы использовать вышеприведенную версию, поскольку понимание списков и itertools часто бывают неожиданно быстрыми, и для распараллеливания потребуются накладные расходы, которые необходимо перевесить.

+0

Ничего себе. Это невероятно ум бесцеремонно быстро. Используя python3, я закончил с: 'df ['course_combined'] = [str (a) .join (b) для (a, b) в itertools.zip_longest (df ['col1'], df ['col2' ])] ' Pandas должен делать что-то очень неэффективное с iloc, я бы подумал, что это был бы быстрый, но уродливый способ перебора данных. – Christopher

1

Один прекрасный способ создать новый столбец в pandas или dask.dataframe с помощью метода .assign.

In [1]: import pandas as pd 

In [2]: df = pd.DataFrame({'x': [1, 2, 3, 4], 'y': ['a', 'b', 'a', 'b']}) 

In [3]: df 
Out[3]: 
    x y 
0 1 a 
1 2 b 
2 3 a 
3 4 b 

In [4]: df.assign(z=df.x * df.y) 
Out[4]: 
    x y  z 
0 1 a  a 
1 2 b bb 
2 3 a aaa 
3 4 b bbbb 

Однако, если ваша операция весьма обычай (как это, кажется), и если Python итераторы достаточно быстро (так как они кажутся), то вы можете просто хотите придерживаться этого. В любое время, когда вы используете apply или iloc в петле, вполне вероятно, что Pandas работает намного медленнее, чем оптимально.