簡體   English   中英

將值設置為 Pandas DataFrame 單元格

[英]Set value into pandas DataFrame cell

我有兩個數據幀:

source_df ( source_df.shape == (1008, 27797) ):

|id   |field_1|  pubs  | users |...|user_1    |user_2    |user_3    |...|user_27769    |
|-----|-------|--------|-------|...|----------|----------|----------|...|--------------|
| 1   |-------|[7, 10] |[1,2,3]|...| x_1_1    | x_2_1    | x_3_1    |...| x_27769_1    |
| 2   |-------|[13, 15]|[2,10] |...| x_1_2    | x_2_2    | x_3_2    |...| x_27769_2    |
|..   |.......|........|[1,2,9]|...|..........|..........|..........|...|..............|
| 1008|-------|[1,2,13]|[7,8,9]|...| x_1_1008 | x_2_1008 | x_3_1008 |...| x_27769_1008 |

user_pub_df ( user_pub_df.shape = (21, 27769) ):

|id| user_1 | user_2 | user_3 |...| user_27769 |
|--|--------|--------|--------|...|------------|
| 1|   10   |   0    |   7    |...|     0      |
| 2|   0    |   0    |   0    |...|     1      |
| 3|   0    |   8    |   4    |...|     0      |
|..|   .    |   .    |   .    |...|     .      |
| 7|   13   |   1    |   6    |...|     0      |
|10|   1    |   1    |   0    |...|     0      |
|13|   1    |   1    |   0    |...|     0      |
|15|   1    |   1    |   0    |...|     19     |

Id這里是一個IDS pubs從列source_df

任務是用來自user_pub_df值填充source_df

source_df.loc[1, 'user_1'] = user_pub_df.loc[7, 'user_1'] + user_pub_df.loc[10, 'user_1'] # 11
source_df.loc[1, 'user_2'] = user_pub_df.loc[7, 'user_2'] + user_pub_df.loc[10, 'user_2'] # 2
source_df.loc[1, 'user_3'] = user_pub_df.loc[7, 'user_3'] + user_pub_df.loc[10, 'user_3'] # 6
source_df.loc[2, 'user_2'] = user_pub_df.loc[13, 'user_2'] + user_pub_df.loc[15, 'user_2'] # 2
source_df.loc[2, 'user_10'] = user_pub_df.loc[13, 'user_10'] + user_pub_df.loc[15, 'user_10'] # 0
# and so on

我用循環做到了:

for index, row in source_df.iterrows():
    for user_id in row['users']:
        source_df.loc[index, 'user_{}'.format(user_id)] = user_pub_df.loc[row['pubs'], user_id].sum()

對於 27769 個用戶和 21 個 pub(約 16 分鍾)來說,原始代碼的工作速度太慢。

我嘗試將.loc更改為.at相同的結果。

PS: source_df可以更改,因此我不能僅將所有user / pubs組合保存到帶有關鍵user+pubs和預計算值的字典/hashmap 中。

如果您使用 df.iloc(index) 而不是 df.loc(index) 它應該更快

我已經調整了代碼以在循環中使用 numpy 數組,然后在最后將其設置到數據幀中。 這跳過了熊貓數據幀中發生的很多索引檢查等。 我認為我的方法一和方法二都會更快,但方法二應該在大量用戶的情況下表現更好

import numpy as np
n_users = user_pub_df.shape[1]
n_rows = source_df.shape[0]
arr = np.zeros((n_rows, n_users))
for index, row in source_df.iterrows():
    for user_id in row['users']:
        arr[index, user_id] = user_pub_df.iloc[row['pubs'], user_id].sum()

source_df.loc[:, 'user_1': 'user_' + str(n_users)] = arr

這是我的測試代碼:

import pandas as pd
import numpy as np
import numpy.ma as ma
import timeit

source_df = pd.DataFrame({
    'pubs': [[1,2],[0,2],[1,0]],
    'users': [[1,2],[0,2],[1,0]],
    'user_1': [1,2,3],
    'user_2': [1,2,3],
    'user_3': [3,2,1]
    })

user_pub_df = pd.DataFrame({
    'user_1': [1,2,3],
    'user_2': [1,2,3],
    'user_3': [3,2,1]
    })
n_users = user_pub_df.shape[1]
n_rows = source_df.shape[0]

def one() :
    global source_df
    arr = []
    for index, row in source_df.iterrows():
        mx = np.ones((len(row['pubs']), n_users))
        mx[:,row['users']] = 0
        arr.append(ma.masked_array(user_pub_df.iloc[row['pubs'],:].values,mask = mx).sum())

    source_df.loc[:, 'user_1': 'user_' + str(n_users)] = arr
    source_df = source_df.fillna(0).copy()

def two() :
    arr = np.zeros((n_rows, n_users))
    for index, row in source_df.iterrows():
        for user_id in row['users']:
            arr[index, user_id] = user_pub_df.iloc[row['pubs'], user_id].sum()

    source_df.loc[:, 'user_1': 'user_' + str(n_users)] = arr

def old() :
    for index, row in source_df.iterrows():
        for user_id in row['users']:
            source_df.loc[index, 'user_{}'.format(user_id)] = user_pub_df.iloc[row['pubs'], user_id].sum()

print(timeit.timeit(old, number =1000))
print(timeit.timeit(one, number =1000))
print(timeit.timeit(two, number =1000))

結果是:

5.25ms

3.83ms

3.65ms

您的數據結構會阻止任何矢量化,您不能期望全速操作:-(。

您可以嘗試的最好方法是直接使用底層 numpy 數組來避免熊貓為每行構建一個新系列:

for i, index in enumerate(source_df.index):
    for user_id in df['users'].values[i]:
        source_df.loc[index, 'user_{}'.format(user_id)] = user_pub_df.loc[df['pubs'].values[i],
                                                                          user_id].sum()

但我不應該對它期望太多......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM