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


131

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

내 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. ]

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


21
2017+ 이상에서이 답변을 찾는 사람들을 위해 아래에 새로운 관용 솔루션이 있습니다 . 당신은 그냥 사용할 수 있습니다list(df.itertuples(index=False, name=None))
Ted Petrou

3
내가이 질문에 올 때 내가 찾고있는 두 가지 : 튜플 목록- df.to_records(index=False)그리고 dicts 목록 :df.to_dict('records')
Martin Thoma

@MartinThoma to_records와 to_dict ( 'records')는 내 데이터 유형을 망칩니다. 알려진 버그이지만이 솔루션을 무가치하게 만듭니다 ...
Jochen

답변:


206

어때요?

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]

2
를 사용하려면 아래 @ksindi의 대답을 참조하십시오. .itertuples이 값은 배열로 값을 가져 와서 튜플로 만드는 것보다 효율적입니다.
vy32

1
약간 청소기는 다음과 같습니다 튜플 =지도 (튜플, subset.values)
RufusVS

그래도 값을 다른 유형으로 캐스트 할 수 있습니다.
AMC

160
list(data_set.itertuples(index=False))

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

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

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

39
이것은 정답 IMHO이어야합니다 (이제 전용 기능이 존재 함). BTW, tuples zip대신 iterator 에서 일반 s 를 원하면 namedtuple다음으로 전화하십시오.data_set.itertuples(index=False, name=None)
Axel


3
@coldspeed 내가 연결된 질문에서 얻은 교훈은 튜플로 변환하는 것이 일반적으로 벡터화 / Cython 연산보다 느리기 때문에 itertuples가 느리다는 것입니다. 질문이 튜플로 변환하도록 요청하면 허용되는 답변이 더 빠르다고 생각할만한 이유가 있습니까? 내가 한 빠른 테스트는 itertuples 버전이 더 빠르다는 것을 나타냅니다.
TC Proctor


1
@ johnDanger 파이썬의 eval () 및 globals () 개념과 유사합니다. 누구나 자신이 존재한다는 것을 알고 있습니다. 또한이 기능은 잘못된 형식으로 간주되므로 일반적으로 이러한 기능을 사용해서는 안된다는 것을 알고 있습니다. 여기의 원리는 비슷합니다. 판다에서 iter * 패밀리를 사용하는 경우는 거의 없습니다. 나는 여전히 다른 방법 (목록 comp 또는 맵과 같은)을 사용하지만 그게 나입니다.
cs95


30

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

비교를 위해 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()

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


12

다음 과 같이 의 를 반환 하는 벡터화 된 접근 방식 (데이터 프레임을 가정하고 대신 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

10

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

list(data_set.to_records())

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


1
'index = False'는 to_records ()에 대한 인수로 제공되어야한다고 생각합니다. 따라서 list (data_set.to_records (index = False))
user3415167

8

이 답변은 아직 논의되지 않은 답변을 추가하지는 않지만 몇 가지 속도 결과가 있습니다. 나는 이것이 의견에서 제기 된 질문을 해결해야한다고 생각합니다. 이 세 가지 값을 기준 으로이 모든 것이 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 버전은 서로 신뢰 구간 내에 있습니다. 나는 그들이 후드 아래에서 같은 일을하고 있다고 생각합니다.

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


부실 게시물을 업데이트했습니다. 나는 [*zip(*map(df.get, df))]언젠가 사용 하고 있었다. 어쨌든, 당신이 흥미로울 것이라고 생각했습니다.
piRSquared

@piRSquared 우우. 나는 예쁜 줄거리를 좋아한다. 나는 그것이 O (n) 인 것처럼 보인다고 생각합니다 .
TC Proctor 2011

2
#try this one:

tuples = list(zip(data_set["data_date"], data_set["data_1"],data_set["data_2"]))
print (tuples)

2

데이터 프레임 목록을 튜플 목록으로 변경

df = pd.DataFrame({'col1': [1, 2, 3], 'col2': [4, 5, 6]})
print(df)
OUTPUT
   col1  col2
0     1     4
1     2     5
2     3     6

records = df.to_records(index=False)
result = list(records)
print(result)
OUTPUT
[(1, 4), (2, 5), (3, 6)]

1
코드를 답변으로 게시 할뿐만 아니라 코드의 기능과 질문의 문제를 해결하는 방법에 대한 설명도 제공하십시오. 설명이 포함 된 답변은 일반적으로 품질이 높으며 투표를 유도 할 가능성이 높습니다.
마크 Rotteveel

1

더 파이썬적인 방법 :

df = data_set[['data_date', 'data_1', 'data_2']]
map(tuple,df.values)

더 파이썬적인 방법 : 사실은 정반대입니다. map()악명 높은 비현실적입니다.
AMC
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.