numpy 提高Pandas DataFrame上的行追加性能

uhry853o  于 2022-11-23  发布在  其他
关注(0)|答案(7)|浏览(171)

我正在运行一个基本脚本,该脚本在嵌套字典中循环,从每条记录中获取数据,并将其追加到Pandas DataFrame中。

data = {"SomeCity": {"Date1": {record1, record2, record3, ...}, "Date2": {}, ...}, ...}

它总共有几百万条记录。脚本本身看起来像这样:

city = ["SomeCity"]
df = DataFrame({}, columns=['Date', 'HouseID', 'Price'])
for city in cities:
    for dateRun in data[city]:
        for record in data[city][dateRun]:
            recSeries = Series([record['Timestamp'], 
                                record['Id'], 
                                record['Price']],
                                index = ['Date', 'HouseID', 'Price'])
            FredDF = FredDF.append(recSeries, ignore_index=True)

然而,这运行得非常慢。在我寻找并行化它的方法之前,我只想确保我没有错过一些明显的东西,这些东西会使它运行得更快,因为我对Pandas还很陌生。

wbgh16ku

wbgh16ku1#

我还在循环中使用了dataframe的append函数,我对它的运行速度感到困惑。
一个有用的例子,为那些谁是痛苦的,根据正确的答案在这一页。
Python版本:3
Pandas版:0.20.3

# the dictionary to pass to pandas dataframe
d = {}

# a counter to use to add entries to "dict"
i = 0 

# Example data to loop and append to a dataframe
data = [{"foo": "foo_val_1", "bar": "bar_val_1"}, 
       {"foo": "foo_val_2", "bar": "bar_val_2"}]

# the loop
for entry in data:

    # add a dictionary entry to the final dictionary
    d[i] = {"col_1_title": entry['foo'], "col_2_title": entry['bar']}
    
    # increment the counter
    i = i + 1

# create the dataframe using 'from_dict'
# important to set the 'orient' parameter to "index" to make the keys as rows
df = DataFrame.from_dict(d, "index")

"from_dict"函数:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.from_dict.html

b5lpy0ml

b5lpy0ml2#

向列表追加行比向DataFrame追加行要高效得多。
1.将行追加到列表中。
1.然后将其转换为DataFrame
1.根据需要设置索引。

polhcujo

polhcujo3#

我认为最好的方法是,如果你知道你将要接收的数据,提前分配。

import numpy as np
import pandas as pd

random_matrix = np.random.randn(100, 100)
insert_df = pd.DataFrame(random_matrix)

df = pd.DataFrame(columns=range(100), index=range(200))
df.loc[range(100), df.columns] = random_matrix
df.loc[range(100, 200), df.columns] = random_matrix

这是我认为最有意义的模式。如果 Dataframe 非常小,append会更快,但它不能伸缩。

In [1]: import numpy as np; import pandas as pd

In [2]: random_matrix = np.random.randn(100, 100)
   ...: insert_df = pd.DataFrame(random_matrix)
   ...: df = pd.DataFrame(np.random.randn(100, 100))

In [2]: %timeit df.append(insert_df)
272 µs ± 2.36 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [3]: %timeit df.loc[range(100), df.columns] = random_matrix
493 µs ± 4.25 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [4]: %timeit df.loc[range(100), df.columns] = insert_df
821 µs ± 8.68 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

当我们使用100,000行 Dataframe 运行此操作时,我们看到了更加显著的结果。

In [1]: df = pd.DataFrame(np.random.randn(100_000, 100))

In [2]: %timeit df.append(insert_df)
17.9 ms ± 253 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [3]: %timeit df.loc[range(100), df.columns] = random_matrix
465 µs ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [4]: %timeit df.loc[range(99_900, 100_000), df.columns] = random_matrix
465 µs ± 5.75 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [5]: %timeit df.loc[range(99_900, 100_000), df.columns] = insert_df
1.02 ms ± 3.42 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

因此,我们可以看到,追加比插入 Dataframe 慢17倍,比插入numpy数组慢35倍。

hiz5n14c

hiz5n14c4#

另一种方法是将其制成列表,然后使用pd.concat

import pandas as pd 

df = pd.DataFrame({'num_legs': [2, 4, 8, 0],

                   'num_wings': [2, 0, 0, 0],

                   'num_specimen_seen': [10, 2, 1, 8]},

                  index=['falcon', 'dog', 'spider', 'fish'])

def append(df):
    df_out = df.copy()
    for i in range(1000):
        df_out = df_out.append(df)
    return df_out

def concat(df):
    df_list = []
    for i in range(1001):
        df_list.append(df)

    return pd.concat(df_list)

# some testing
df2 = concat(df)
df3 = append(df)

pd.testing.assert_frame_equal(df2,df3)

%timeit concat(df)
20.2 ms ± 794 µs/循环(7次运行的平均值±标准差,每次100次循环)
%timeit append(df)
275 ms ± 2.54 ms/循环(7次运行的平均值±标准差,每次1个循环)
现在,建议使用以下方式连接pandom中的行:
迭代地将行追加到DataFrame比单个连接需要更大的计算量。更好的解决方案是将这些行追加到列表,然后一次性将该列表与原始DataFrame连接在一起。link

j1dl9f46

j1dl9f465#

我遇到了一个类似的问题,我不得不多次向DataFrame追加,但是在追加之前不知道值。()。我用它来累积所有的数据,然后在完成时将输出转换为Pandas DataFrame。下面是我的项目的链接,都是开源的,所以我希望它能帮助其他人:
https://pypi.python.org/pypi/raccoon

csbfibhn

csbfibhn6#

在我的例子中,我从不同的文件中加载了大量具有相同列的 Dataframe ,并希望将它们追加到一个大型 Dataframe 中。
我的解决方案是首先将所有 Dataframe 加载到列表中,然后使用

all_dfs = []
for i in all_files:
  all_dfs.append(/* load df from file */)

master_df = pd.concat(all_dfs, ignore_index=True)
col17t5w

col17t5w7#

N=100000

t0=time.time()
d=[]
for i in range(N):
    d.append([i, i+1,i+2,i+3,i+0.1,1+0.2])
testdf=pd.DataFrame.from_records(d, columns=["x1","x2","x3","x4", "x5", "x6"])
print(time.time()-t0)

t0=time.time()
d={}
for i in range(N):
    d[len(d)+1]={"x1":i, "x2":i+1, "x3":i+2,"x4":i+3,"x5":i+0.1,"x6":1+0.2}
testdf=pd.DataFrame.from_dict(d, "index")
print(time.time()-t0)

t0=time.time()
testdf=pd.DataFrame()
for i in range(N):
    testdf=testdf.append({"x1":i, "x2":i+1, "x3":i+2,"x4":i+3,"x5":i+0.1,"x6":1+0.2}, ignore_index=True)
print(time.time()-t0)

=== result for N=10000 ===
list:0.016329050064086914
dict:0.03952217102050781
DataFrame:10.598219871520996

=== result for N=100000 ===
list: 0.4076499938964844
dict: 0.45696187019348145
DataFrame: 187.6609809398651

相关问题