당신의 CSV가 긴 줄의 수천의 경우, using_string_methods
(아래) 있을 수 있습니다보다 빠른 using_iterrows
또는 using_repeat
:
으로
csv = 'id|name|fields'+("""
1|abc|[qq,ww,rr]
2|efg|[zz,xx,rr]"""*10000)
In [210]: %timeit using_string_methods(csv)
10 loops, best of 3: 100 ms per loop
In [211]: %timeit using_itertuples(csv)
10 loops, best of 3: 119 ms per loop
In [212]: %timeit using_repeat(csv)
10 loops, best of 3: 126 ms per loop
In [213]: %timeit using_iterrows(csv)
1 loop, best of 3: 1min 7s per loop
따라서 10000 라인 CSV의 경우 using_string_methods
은 using_iterrows
보다 600 배 이상 빠르며 using_repeat
보다 약간 빠릅니다. 데이터가 (당신이 목록을 배치하면 (예 : int64
또는 float64
, 또는 문자열. 등) 기본 NumPy와의 DTYPE 경우에만
import pandas as pd
try: from cStringIO import StringIO # for Python2
except ImportError: from io import StringIO # for Python3
def using_string_methods(csv):
df = pd.read_csv(StringIO(csv), sep='|', dtype=None)
other_columns = df.columns.difference(['fields']).tolist()
fields = (df['fields'].str.extract(r'\[(.*)\]', expand=False)
.str.split(r',', expand=True))
df = pd.concat([df.drop('fields', axis=1), fields], axis=1)
result = (pd.melt(df, id_vars=other_columns, value_name='field')
.drop('variable', axis=1))
result = result.dropna(subset=['field'])
return result
def using_iterrows(csv):
df = pd.read_csv(StringIO(csv), sep='|')
df.fields = df.fields.apply(lambda s: s[1:-1].split(','))
new_df = pd.DataFrame(index=[], columns=df.columns)
for _, i in df.iterrows():
flattened_d = [dict(i.to_dict(), fields=c) for c in i.fields]
new_df = new_df.append(flattened_d)
return new_df
def using_repeat(csv):
df = pd.read_csv(StringIO(csv), sep='|')
df.fields = df.fields.apply(lambda s: s[1:-1].split(','))
cols = df.columns[df.columns != 'fields'].tolist()
df1 = pd.DataFrame(np.column_stack(
(df[cols].values.repeat(list(map(len,df.fields)),axis=0),
np.hstack(df.fields))), columns=cols + ['fields'])
return df1
def using_itertuples(csv):
df = pd.read_csv(StringIO(csv), sep='|')
df.fields = df.fields.apply(lambda s: s[1:-1].split(','))
other_columns = df.columns.difference(['fields']).tolist()
data = []
for tup in df.itertuples():
data.extend([[getattr(tup, col) for col in other_columns]+[field]
for field in tup.fields])
return pd.DataFrame(data, columns=other_columns+['field'])
csv = 'id|name|fields'+("""
1|abc|[qq,ww,rr]
2|efg|[zz,xx,rr]"""*10000)
일반적으로, 빠른 NumPy와/팬더 작업이 가능합니다 치명적인 NumPy dtype)을 사용하여 지그가 올라간 경우 - 은 파이썬 속도의 루프를 사용하여 목록을 처리해야합니다.
성능을 향상 시키려면 목록을 DataFrame에 배치하지 않아야합니다.
df = pd.read_csv(StringIO(csv), sep='|', dtype=None)
과 (일반 파이썬 루프로 일반적으로 느린)에 apply
방법을 사용하지 마십시오 :
using_string_methods
문자열로 fields
데이터를로드하는 대신
df.fields = df.fields.apply(lambda s: s[1:-1].split(','))
을 더 빨리 사용 문자열을 개로 분리하는 벡터화 된 문자열 메서드
fields = (df['fields'].str.extract(r'\[(.*)\]', expand=False)
.str.split(r',', expand=True))
별도의 열에 필드가 있으면 pd.melt
을 사용하여 DataFrame을 원하는 형식으로 바꿀 수 있습니다.
pd.melt(df, id_vars=['id', 'name'], value_name='field')
그런데
, 당신은 약간의 수정과 함께 그것을보고 관심을 가질만한 using_iterrows
단지 빨리 using_repeat
로 될 수 있습니다. 변경 내용을 using_itertuples
에 표시합니다. df.itertuples
은 df.iterrows
보다 약간 빠른 경향이 있지만 그 차이는 미미합니다. 대부분의 속도 증가는 을 for 루프로 호출하지 않으므로 실현됩니다. leads to quadratic copying 이후입니다.
첫 번째 명령이 실패합니다. 오류는'MergeError : 병합을 수행 할 공통 열이 없음' – yuval
죄송합니다. 인덱스 값을 기반으로 작동하는'join'을 사용하려고했습니다. 내 대답을 바로 잡았어. – cmaher
아직도 작동하지 않습니다.결과는 다음과 같습니다 (한 줄로 표시). 'id name level_2 0 0 1 abc fields [qq, ww, rr] 1 2 efg fields [zz, xx, rr] ' – yuval