【发布时间】:2017-05-06 13:56:04
【问题描述】:
当我在 pandas 中有一个数据框时:
raw_data = {
'subject_id': ['1', '2', '3', '4', '5'],
'name': ['A', 'B', 'C', 'D', 'E'],
'nationality': ['DE', 'AUT', 'US', 'US', 'US'],
'alotdifferent': ['x', 'y', 'z', 'x', 'a'],
'target': [0,0,0,1,1],
'age_group' : [1, 2, 1, 3, 1]}
df_a = pd.DataFrame(raw_data, columns = ['subject_id', 'name', 'nationality', 'alotdifferent','target','age_group'])
df_a.nationality = df_a.nationality.astype('category')
df_a.alotdifferent = df_a.alotdifferent.astype('category')
df_a.name = df_a.name.astype('category')
目前,我使用:
FACTOR_FIELDS = df_a.select_dtypes(include=['category']).columns
columnsToDrop = ['alotdifferent']
columnsToBias_keep = FACTOR_FIELDS[~FACTOR_FIELDS.isin(columnsToDrop)]
target = 'target'
def quotients_slow(df_a):
# parallelism = 8
# original = dd.from_pandas(df.copy())
original = df_a.copy()
output_df = original
ratio_weights = {}
for colname in columnsToBias_keep.union(columnsToDrop):
# group only a single time
grouped = original.groupby([colname, target]).size()
# calculate first ratio
df = grouped / original[target].sum()
nameCol = "pre_" + colname
grouped_res = df.reset_index(name=nameCol)
grouped_res = grouped_res[grouped_res[target] == 1]
grouped_res = grouped_res.drop(target, 1)
# todo persist the result in dict for transformer
result_1 = grouped_res
# calculate second ratio
df = (grouped / grouped.groupby(level=0).sum())
nameCol_2 = "pre2_" + colname
grouped = df.reset_index(name=nameCol_2)
grouped_res = grouped[grouped[target] == 1]
grouped_res = grouped_res.drop(target, 1)
result_2 = grouped_res
# persist the result in dict for transformer
# this is required to separate fit and transform stage (later on in a sklearn transformer)
ratio_weights[nameCol] = result_1
ratio_weights[nameCol_2] = result_2
# retrieve results
res_1 = ratio_weights['pre_' + colname]
res_2 = ratio_weights['pre2_' + colname]
# merge ratio_weight with original dataframe
output_df = pd.merge(output_df, res_1, on=colname, how='left')
output_df = pd.merge(output_df, res_2, on=colname, how='left')
output_df.loc[(output_df[nameCol].isnull()), nameCol] = 0
output_df.loc[(output_df[nameCol_2].isnull()), nameCol_2] = 0
if colname in columnsToDrop:
output_df = output_df.drop(colname, 1)
return output_df
quotients_slow(df_a)
以两种方式计算每个(分类)列的每个组与target:1 的比率。由于我想对多个列执行此操作,因此我天真地迭代了所有列。但是这个操作很慢。
在示例中:10 loops, best of 3: 37 ms per loop。对于我大约 500000 行和大约 100 列的真实数据集,这确实需要一段时间。
难道不应该在 dask 或 pandas 中加快速度(列并行方式、简单并行化)吗?是否有可能在普通熊猫中更有效地实施它?是否可以减少计算商的数据传递次数?
编辑
当尝试在 for 循环中使用 dask.delayed 来实现列上的并行性时,我不知道如何在列上构建图形,因为我需要调用 compute获取元组。
delayed_res_name = delayed(compute_weights)(df_a, 'name')
a,b,c,d = delayed_res_name.compute()
ratio_weights = {}
ratio_weights[c] = a
ratio_weights[d] = b
【问题讨论】:
-
也许单次通过类似于这里的演示:jcrist.github.io/dask-sklearn-part-3.html
-
"
target列与任何其他列的百分比..." 您在此处的计算得出了一种不寻常的比例。例如,name:A/target:0组合出现在 5 个观察值中的 1 个中。但是您将1 occurrence除以target中1值的总和。想象一下,如果您有 3 个name:A/target:0条目,但在target中仍然只有两个1值。name:A/target:0的比例应该是 1.5 还是 150%? -
你可能是对的,我需要考虑这一点,但重点是我想并行化/有效地实现这样的划分(某种百分比)。实际上,
target:0是无关紧要的。我只对target:1感兴趣,或者换一种方式指出:target:1/allRecords每组每列的比例。也许这是一个更好的表述。 -
在这种情况下,请考虑使用您的确切用例更新问题的正文。计算过程本身对于解决您关于效率的问题可能很重要,因为 Pandas 对某些操作和操作序列进行了内置优化。
-
要明确,如果
name:A在一个总共有5个观察值的数据集中出现3次,而name:A/target:1出现1次,那么name:A/的所需比例计算target:1分组应该是 0.33?
标签: python pandas parallel-processing dask