Python获得pandas数据帧中所有特征组合的条件概率

时间:2018-01-26 05:49:09

标签: python performance pandas numpy statistics

我有一个带有一些分类变量的Pandas数据框。像这样的东西 -

>>df
 'a', 'x'
 'a', 'y'

现在,我想返回一个矩阵,其中每个级别的条件概率出现在每个其他级别。对于上面的数据框,它看起来像 -

[1, 0.5, 0.5],
[1, 1, 0],
[1, 0, 1]

这三个条目对应于“a”,“x”和“y”等级。

这是因为条件是第一列为'a',出现'x'和'y'的概率为0.5,依此类推。 我有一些代码可以做到这一点(下面)。然而,问题在于它极其缓慢。这个应用程序我想要在时间上使用它的速度太慢了。有没有人有任何提示让它更快?

df = pd.read_csv('pathToData.csv')
df = df.fillna("null")
cols = 0
col_levels = []
columns = {}
num = 0
for i in df.columns:
cols += len(set(df[i]))
col_levels.append(np.sort(list(set(df[i]))))
for j in np.sort(list(set(df[i]))):
    columns[i + '_' + str(j)] = num
    num += 1

res = np.eye(cols)

for i in range(len(df.columns)):
  for j in range(len(df.columns)):
    if i != j:
        row_feature = df.columns[i]
        col_feature = df.columns[j]
        rowLevels = col_levels[i]
        colLevels = col_levels[j]
        for ii in rowLevels:
            for jj in colLevels:                
                frst = (df[row_feature] == ii) * 1
                scnd = (df[col_feature] == jj) * 1
                prob = sum(frst*scnd)/(sum(frst) + 1e-9)
                frst_ind = columns[row_feature + '_' + ii]
                scnd_ind = columns[col_feature + '_' + jj]
                res[frst_ind, scnd_ind] = prob

编辑:这是一个更大的例子:

>>df
'a', 'x', 'l'
'a', 'y', 'l'
'b', 'x', 'l'

这里不同类别的数量是'a','b','x','y'和'l'。由于这些是5类,因此输出矩阵应为5x5。第一行和第一列是“a”以“a”为条件出现的频率。这当然是1(和所有对角线一样)。第一行和第二列以'a'为条件,'b'的概率是多少。由于'a'和'b'是同一列的一部分,因此该值为零。第一行和第三列是'x'以'a'为条件的概率。我们看到'a'出现两次,但只有'x'出现一次。所以,这个概率是0.5。等等。

1 个答案:

答案 0 :(得分:1)

我解决问题的方法是首先计算数据集中的所有唯一级别。然后循环通过这些级别的笛卡尔积。在每个步骤中,过滤数据集以创建条件为True的子集。然后,计算事件发生的子集中的行数。以下是我的代码。

import pandas as pd
from itertools import product
from collections import defaultdict

df = pd.DataFrame({
    'col1': ['a', 'a', 'b'],
    'col2': ['x', 'y', 'x'],
    'col3': ['l', 'l', 'l']
})

levels = df.stack().unique()

res = defaultdict(dict)
for event, cond in product(levels, levels):

    # create a subset of rows with at least one element equal to cond
    conditional_set = df[(df == cond).any(axis=1)]
    conditional_set_size = len(conditional_set)

    # count the number of rows in the subset where at least one element is equal to event
    conditional_event_count = (conditional_set == event).any(axis=1).sum()

    res[event][cond] = conditional_event_count / conditional_set_size

result_df = pd.DataFrame(res)
print(result_df)

# OUTPUT    
#       a         b    l         x         y
# a  1.000000  0.000000  1.0  0.500000  0.500000
# b  0.000000  1.000000  1.0  1.000000  0.000000
# l  0.666667  0.333333  1.0  0.666667  0.333333
# x  0.500000  0.500000  1.0  1.000000  0.000000
# y  1.000000  0.000000  1.0  0.000000  1.000000

我确信还有其他更快的方法,但这是我想到的第一件事。