I have manipulated some data using pandas and now I want to carry out a batch save back to the database. This requires me to convert the dataframe into an array of tuples, with each tuple corresponding to a “row” of the dataframe.
from simple_benchmark importBenchmarkBuilder
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
1002.9056626.6263083.4507411.4694711.0000003164.6126924.8144332.3758741.0963521.00000010006.5131214.1064261.9582931.0000001.31630331628.4461384.0821611.8083391.0000001.533605100008.4244833.6214611.6518311.0000001.558592316227.8138033.3865921.5864831.0000001.5154781000007.0505723.1624261.4999771.0000001.480131
Motivation
Many data sets are large enough that we need to concern ourselves with speed/efficiency. So I offer this solution in that spirit. It happens to also be succinct.
For the sake of comparison, let’s drop the index column
It happens to also be flexible if we wanted to deal with a specific subset of columns. We’ll assume the columns we’ve already displayed are the subset we want.
The idea of setting datetime column as the index axis is to aid in the conversion of the Timestamp value to it’s corresponding datetime.datetime format equivalent by making use of the convert_datetime64 argument in DF.to_records which does so for a DateTimeIndex dataframe.
This returns a recarray which could be then made to return a list using .tolist
More generalized solution depending on the use case would be:
df.to_records().tolist() # Supply index=False to exclude index
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)
This answer doesn’t add any answers that aren’t already discussed, but here are some speed results. I think this should resolve questions that came up in the comments. All of these look like they are O(n), based on these three values.
TL;DR: tuples = list(df.itertuples(index=False, name=None)) and tuples = list(zip(*[df[c].values.tolist() for c in df])) are tied for the fastest.
I did a quick speed test on results for three suggestions here:
The zip answer from @pirsquared: tuples = list(zip(*[df[c].values.tolist() for c in df]))
The accepted answer from @wes-mckinney: tuples = [tuple(x) for x in df.values]
The itertuples answer from @ksindi with the name=None suggestion from @Axel: 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)})
Small size:
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))
Gives:
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)
Larger:
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))
Gives:
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)
As much patience as I have:
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))
Gives:
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)
The zip version and the itertuples version are within the confidence intervals each other. I suspect that they are doing the same thing under the hood.
These speed tests are probably irrelevant though. Pushing the limits of my computer’s memory doesn’t take a huge amount of time, and you really shouldn’t be doing this on a large data set. Working with those tuples after doing this will end up being really inefficient. It’s unlikely to be a major bottleneck in your code, so just stick with the version you think is most readable.
回答 7
#try this one:
tuples = list(zip(data_set["data_date"], data_set["data_1"],data_set["data_2"]))print(tuples)