嘗試將 pandas 系列合并在一起時遇到一個小問題,感謝您的幫助。
我有一個包含 30M 行的大檔案。我無法將所有資料都保存在記憶體中,因此我在 pandas.read_csv 方法中使用了選項 chunksize。
這是我必須決議的檔案的示例。它代表用戶對應用程式內某些模塊的訪問。我用 x 替換了時間,因為在這種情況下它并不重要。我們有關于每個用戶 (user_id)、他們訪問的時間和模塊 (module_id) 的資料。
user_id;time;module_id
1;x;101
1;x;101
1;x;102
1;x;102
2;x;102
2;x;102
2;x;103
我的任務是瀏覽整個檔案并找出每個用戶訪問每個模塊的次數。我還有另一個資料框(df),其中包含有關每個用戶的資訊。df 的索引是 user_id。
這是我到目前為止的代碼
logs = pd.read_csv(... , chunksize=50000, index_col=user_id)
module_accesses = pd.Series(index = df.index, dtype='object', name=module_id)
for log in logs:
module_accesses = process(log, module_accesses)
def process(log, module_accesses):
# Edit: the line below was added
log[module_id] = log[description].apply(getModuleIdFromDescription)
groups = log.groupby([user_id, module_id]).size()
new_groups = module_accesses groups
return new_groups
當我初始化module_accesses時,它看起來像這樣:
user_id
440250 NaN
428394 NaN
...
746792 NaN
746794 NaN
變數groups看起來像這樣
user_id module_id
592844 272 2
1711 2
6707 1
594073 326 1
3094 1
..
649479 288 9
2302 9
2312 1
651921 251 2
948 1
但是,當我這樣做時new_groups = module_accesses groups,變數new_groups具有此值。
592844 272 NaN
1711 NaN
6707 NaN
594073 326 NaN
3094 NaN
...
649479 288 NaN
2302 NaN
2312 NaN
651921 251 NaN
948 NaN
我希望能夠遍歷每個塊并更新 Serie module_accesses。每個人的訪問次數user_id / module_id應該增加,最后我應該有每個用戶和每個模塊的訪問總數。預期的結果將類似于變數groups,但適用于整個檔案。我們有很多用戶(350k)和模塊(100k)。此外,大多數用戶只能訪問 10-20 個模塊。預期結果示例:
user_id module_id
592844 272 27389
1711 103827
6707 194625
594073 326 2846
3094 103826
..
649479 288 1023
2302 2038
2312 12344
651921 251 829
948 302
uj5u.com熱心網友回復:
我認為您需要module_accesses成為pd.DataFramme,因為您需要跟蹤“每個用戶對模塊的訪問次數”:
module_accesses = pd.DataFrame([], columns=["user_id", "module_id", "n"])
也就是說,我將迭代地合并module_accesses(當前已知訪問)和groups(要注冊的新訪問),然后將訪問次數加入列:
# Slight modification to name the size column "n"
groups = log.groupby(["user_id", "module_id"]).size().to_frame("n")
# Merge known and new accesses
new_groups = pd.merge(module_accesses, groups, how="outer", on=["user_id", "module_id"])
# Combine both counts into a single count
new_groups["n"] = new_groups.pop("n_x").fillna(0) new_groups.pop("n_y").fillna(0)
的結果定義process:
def process(log, module_accesses):
groups = log.groupby(["user_id", "module_id"]).size().to_frame("n")
new_groups = pd.merge(module_accesses, groups, how="outer", on=["user_id", "module_id"])
new_groups["n"] = new_groups.pop("n_x").fillna(0) new_groups.pop("n_y").fillna(0)
return new_groups
另一個想法:
- 使用程序回傳
groups(不計算new_groups) - 在資料幀串列中累積輸出
- 用于
pd.concat創建單個大資料框 - 用于
groupby將大資料框縮減為您預期的格式
uj5u.com熱心網友回復:
問題:
兩個的求和操作
pd.Series是逐個索引進行的,顯然你module_accesses和groups不共享同一組索引,因此它不會像你預期的那樣求和。即使您確保它們具有相同的索引集,將一個數字與 np.nan 相加也會給您一個 np.nan。因此,您可能希望將 module_accesses 初始化為零而不是 NaN。
但是,您可以從另一種方式解決這個問題,因為您有資料集的每個塊的計數,您可以將它們簡單地存盤到一個串列中,并將它們全部連接成一個更大的計數系列,然后您可以groupby再次和簡單地將計數相加。
pd.concat([
log.assign(module_id=log['description'].apply(getModuleIdFromDescription))\
.groupby(['user_id', 'module_id'])\
.size().rename('count')
for log in logs
]).reset_index().groupby(['user_id', 'module_id'])['count'].sum()
請注意,通過這種方式,您將不會看到在任何模塊中都沒有任何計數的 user_id。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/428705.html
