![](/img/trans.png)
[英]Set value for particular cell in pandas DataFrame with iloc
[英]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.