[python] 팬더는 데이터 프레임을 튜플 배열로 변환

팬더를 사용하여 일부 데이터를 조작했으며 이제 데이터베이스에 배치 저장을 다시 수행하려고합니다. 이를 위해서는 데이터 프레임을 튜플 배열로 변환해야하며 각 튜플은 데이터 프레임의 “행”에 해당합니다.

내 DataFrame은 다음과 같습니다.

In [182]: data_set
Out[182]:
  index data_date   data_1  data_2
0  14303 2012-02-17  24.75   25.03
1  12009 2012-02-16  25.00   25.07
2  11830 2012-02-15  24.99   25.15
3  6274  2012-02-14  24.68   25.05
4  2302  2012-02-13  24.62   24.77
5  14085 2012-02-10  24.38   24.61 

나는 그것을 다음과 같은 튜플 배열로 변환하고 싶다 :

[(datetime.date(2012,2,17),24.75,25.03),
(datetime.date(2012,2,16),25.00,25.07),
...etc. ]

이 작업을 효율적으로 수행하는 방법에 대한 제안이 있습니까?



답변

어때요?

subset = data_set[['data_date', 'data_1', 'data_2']]
tuples = [tuple(x) for x in subset.to_numpy()]

팬더 <0.24 사용

tuples = [tuple(x) for x in subset.values]


답변

list(data_set.itertuples(index=False))

17.1 현재는 위 의 namedtuples 목록을 반환합니다 .

일반 튜플 목록을 원하면 name=None인수로 전달하십시오.

list(data_set.itertuples(index=False, name=None))


답변

일반적인 방법 :

[tuple(x) for x in data_set.to_records(index=False)]


답변

동기 부여
많은 데이터 세트는 속도 / 효율성에 대해 우려 할만큼 충분히 큽니다. 그래서 저는 그 정신으로이 솔루션을 제공합니다. 간결한 일이기도합니다.

비교를 위해 index열을 삭제합시다.

df = data_set.drop('index', 1)

솔루션
나는의 사용을 제안합니다 zipmap

list(zip(*map(df.get, df)))

[('2012-02-17', 24.75, 25.03),
 ('2012-02-16', 25.0, 25.07),
 ('2012-02-15', 24.99, 25.15),
 ('2012-02-14', 24.68, 25.05),
 ('2012-02-13', 24.62, 24.77),
 ('2012-02-10', 24.38, 24.61)]

특정 열의 하위 집합을 처리하려는 경우에도 유연합니다. 이미 표시 한 열이 원하는 하위 집합이라고 가정하겠습니다.

list(zip(*map(df.get, ['data_date', 'data_1', 'data_2'])))

[('2012-02-17', 24.75, 25.03),
 ('2012-02-16', 25.0, 25.07),
 ('2012-02-15', 24.99, 25.15),
 ('2012-02-14', 24.68, 25.05),
 ('2012-02-13', 24.62, 24.77),
 ('2012-02-10', 24.38, 24.61)]

빨리 무엇입니까?

턴 아웃 records이 가장 빠르며 점진적으로 수렴 zipmap하고iter_tuples

이 게시물simple_benchmarks 에서 얻은 라이브러리 를 사용하겠습니다

from simple_benchmark import BenchmarkBuilder
b = BenchmarkBuilder()

import pandas as pd
import numpy as np

def tuple_comp(df): return [tuple(x) for x in df.to_numpy()]
def iter_namedtuples(df): return list(df.itertuples(index=False))
def iter_tuples(df): return list(df.itertuples(index=False, name=None))
def records(df): return df.to_records(index=False).tolist()
def zipmap(df): return list(zip(*map(df.get, df)))

funcs = [tuple_comp, iter_namedtuples, iter_tuples, records, zipmap]
for func in funcs:
    b.add_function()(func)

def creator(n):
    return pd.DataFrame({"A": random.randint(n, size=n), "B": random.randint(n, size=n)})

@b.add_arguments('Rows in DataFrame')
def argument_provider():
    for n in (10 ** (np.arange(4, 11) / 2)).astype(int):
        yield n, creator(n)

r = b.run()

결과 확인

r.to_pandas_dataframe().pipe(lambda d: d.div(d.min(1), 0))

        tuple_comp  iter_namedtuples  iter_tuples   records    zipmap
100       2.905662          6.626308     3.450741  1.469471  1.000000
316       4.612692          4.814433     2.375874  1.096352  1.000000
1000      6.513121          4.106426     1.958293  1.000000  1.316303
3162      8.446138          4.082161     1.808339  1.000000  1.533605
10000     8.424483          3.621461     1.651831  1.000000  1.558592
31622     7.813803          3.386592     1.586483  1.000000  1.515478
100000    7.050572          3.162426     1.499977  1.000000  1.480131

r.plot()

여기에 이미지 설명을 입력하십시오


답변

다음 과 같이 의 를 반환 하는 벡터화 된 접근 방식 (데이터 프레임을 가정하고 대신 data_set정의 됨 df)이 있습니다 .listtuples

>>> df.set_index(['data_date'])[['data_1', 'data_2']].to_records().tolist()

생산 :

[(datetime.datetime(2012, 2, 17, 0, 0), 24.75, 25.03),
 (datetime.datetime(2012, 2, 16, 0, 0), 25.0, 25.07),
 (datetime.datetime(2012, 2, 15, 0, 0), 24.99, 25.15),
 (datetime.datetime(2012, 2, 14, 0, 0), 24.68, 25.05),
 (datetime.datetime(2012, 2, 13, 0, 0), 24.62, 24.77),
 (datetime.datetime(2012, 2, 10, 0, 0), 24.38, 24.61)]

날짜 시간 열을 인덱스 축으로 설정하는 아이디어 는 데이터 프레임에 대해 인수를 사용 하여 Timestamp값을 해당 datetime.datetime형식으로 변환하는 데 도움 을주는 것입니다 .convert_datetime64DF.to_recordsDateTimeIndex

이것은를 반환 recarray하고 list사용하여 반환 할 수 있습니다.tolist


사용 사례에 따라보다 일반적인 솔루션은 다음과 같습니다.

df.to_records().tolist()                              # Supply index=False to exclude index


답변

가장 효율적이고 쉬운 방법 :

list(data_set.to_records())

이 호출 전에 필요한 열을 필터링 할 수 있습니다.


답변

이 답변은 아직 논의되지 않은 답변을 추가하지는 않지만 몇 가지 속도 결과가 있습니다. 나는 이것이 의견에서 제기 된 질문을 해결해야한다고 생각합니다. 이 세 가지 값을 기준 으로이 모든 것이 O (n) 인 것처럼 보입니다 .

TL은, DR : tuples = list(df.itertuples(index=False, name=None))tuples = list(zip(*[df[c].values.tolist() for c in df]))가장 빠른 공동된다.

세 가지 제안에 대한 결과에 대한 빠른 속도 테스트를 수행했습니다.

  1. @pirsquared의 우편 답변 : tuples = list(zip(*[df[c].values.tolist() for c in df]))
  2. @ wes-mckinney의 답변 : tuples = [tuple(x) for x in df.values]
  3. itertuples는 @Axel의 name=None제안 과 함께 @ksindi의 답변입니다 .tuples = list(df.itertuples(index=False, name=None))
from numpy import random
import pandas as pd


def create_random_df(n):
    return pd.DataFrame({"A": random.randint(n, size=n), "B": random.randint(n, size=n)})

작은 크기:

df = create_random_df(10000)
%timeit tuples = list(zip(*[df[c].values.tolist() for c in df]))
%timeit tuples = [tuple(x) for x in df.values]
%timeit tuples = list(df.itertuples(index=False, name=None))

제공합니다 :

1.66 ms ± 200 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
15.5 ms ± 1.52 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.74 ms ± 75.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

더 크게 :

df = create_random_df(1000000)
%timeit tuples = list(zip(*[df[c].values.tolist() for c in df]))
%timeit tuples = [tuple(x) for x in df.values]
%timeit tuples = list(df.itertuples(index=False, name=None))

제공합니다 :

202 ms ± 5.91 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
1.52 s ± 98.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
209 ms ± 11.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

내가 가진만큼의 인내심 :

df = create_random_df(10000000)
%timeit tuples = list(zip(*[df[c].values.tolist() for c in df]))
%timeit tuples = [tuple(x) for x in df.values]
%timeit tuples = list(df.itertuples(index=False, name=None))

제공합니다 :

1.78 s ± 118 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
15.4 s ± 222 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
1.68 s ± 96.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Zip 버전과 itertuples 버전은 서로 신뢰 구간 내에 있습니다. 나는 그들이 후드 아래에서 같은 일을하고 있다고 생각합니다.

이 속도 테스트는 아마도 관련이 없습니다. 내 컴퓨터의 메모리의 한계를 추진하는 것은 많은 시간을 고려하지 않습니다, 당신은 정말 큰 데이터 세트에이 일을해서는 안된다. 이 작업을 수행 한 후 해당 튜플을 사용하면 실제로 비효율적입니다. 코드에 큰 병목이 없을 가능성이 높으므로 가장 읽기 쉬운 버전을 고수하십시오.