更有效的方法:value_counts(以 % 为单位)对于按变量分组的许多列
More efficient way for: value_counts (in %) for many columns grouped by a variable
我正在处理一个用例,在该用例中,我对每个 ID 的许多功能进行了很多观察,我需要计算每列每个 ID 的值频率(~5 个离散值)。
我有一个适用于相当小的数据集(例如 < 100 万行)的解决方案,但在我的整个数据集(将来可能会变得更大)上失败,因为它填满了我的 RAM。我找不到一个干净的 groupby 解决方案,因为我需要一次对许多列执行此操作。
示例数据:
import pandas as pd
import numpy as np
n = 100 # Number of features
m = 100 # Number of classes
k = 10000 # number of occurrences per class
possible_values = [1, 2, 3, 4, 5]
df = []
for i in range(m):
for j in range(k):
df.append( np.append(i, np.random.choice(possible_values, n)) )
features = [f"feature{i}" for i in range(n)]
df = pd.DataFrame(df, columns=(["id"] + features))
没有 groupby 的情况很容易:
df[features].apply(pd.value_counts).T / df.shape[0]
我的做法
melted = df.melt(id_vars="id", var_name='feature', value_name='value')
feature_freq_id = pd.crosstab(index=[melted.id, melted.feature], columns=melted.value).reset_index()
feature_freq_id[possible_values] = feature_freq_id[possible_values].div(feature_freq_id[possible_values].sum(axis=1), axis=0)
问题是 melted
有 n*m*k
行。我的数据集具有 >250 个特征、>200 个 ID 和每个 ID 约 5k 个观测值,这意味着 melted
将具有 >2.5 亿行。这导致我的记忆最终被填满,python 死了。
预期结果:
feature_freq_id.head(3)
id
feature
1
2
3
4
5
0
0
feature0
0.183
0.185
0.226
0.187
0.219
1
0
feature1
0.178
0.222
0.209
0.209
0.182
2
0
feature10
0.215
0.213
0.175
0.196
0.201
只是一个想法:使用 groupby
而不是 id
并结合您的“简单”方法:
def fractions(sdf):
return sdf.apply(pd.value_counts, normalize=True).fillna(0.).T
result = df.groupby("id")[features].apply(fractions)
result.index.set_names("feature", level=1, inplace=True)
这应该避免内存 melt
-down?
我正在处理一个用例,在该用例中,我对每个 ID 的许多功能进行了很多观察,我需要计算每列每个 ID 的值频率(~5 个离散值)。
我有一个适用于相当小的数据集(例如 < 100 万行)的解决方案,但在我的整个数据集(将来可能会变得更大)上失败,因为它填满了我的 RAM。我找不到一个干净的 groupby 解决方案,因为我需要一次对许多列执行此操作。
示例数据:
import pandas as pd
import numpy as np
n = 100 # Number of features
m = 100 # Number of classes
k = 10000 # number of occurrences per class
possible_values = [1, 2, 3, 4, 5]
df = []
for i in range(m):
for j in range(k):
df.append( np.append(i, np.random.choice(possible_values, n)) )
features = [f"feature{i}" for i in range(n)]
df = pd.DataFrame(df, columns=(["id"] + features))
没有 groupby 的情况很容易:
df[features].apply(pd.value_counts).T / df.shape[0]
我的做法
melted = df.melt(id_vars="id", var_name='feature', value_name='value')
feature_freq_id = pd.crosstab(index=[melted.id, melted.feature], columns=melted.value).reset_index()
feature_freq_id[possible_values] = feature_freq_id[possible_values].div(feature_freq_id[possible_values].sum(axis=1), axis=0)
问题是 melted
有 n*m*k
行。我的数据集具有 >250 个特征、>200 个 ID 和每个 ID 约 5k 个观测值,这意味着 melted
将具有 >2.5 亿行。这导致我的记忆最终被填满,python 死了。
预期结果:
feature_freq_id.head(3)
id | feature | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|---|
0 | 0 | feature0 | 0.183 | 0.185 | 0.226 | 0.187 | 0.219 |
1 | 0 | feature1 | 0.178 | 0.222 | 0.209 | 0.209 | 0.182 |
2 | 0 | feature10 | 0.215 | 0.213 | 0.175 | 0.196 | 0.201 |
只是一个想法:使用 groupby
而不是 id
并结合您的“简单”方法:
def fractions(sdf):
return sdf.apply(pd.value_counts, normalize=True).fillna(0.).T
result = df.groupby("id")[features].apply(fractions)
result.index.set_names("feature", level=1, inplace=True)
这应该避免内存 melt
-down?