【问题标题】:pandas loop to run multiple cross tabs熊猫循环运行多个交叉表
【发布时间】:2021-06-10 11:46:52
【问题描述】:

我有以下数据集,我想以最有效的方式计算交叉表的所有可能组合,我已经能够针对一个主变量计算对,但不是针对所有可能性(我已经弹出了我的意思在下面)。有没有办法让这一切都在循环中,可以处理任意数量的列?非常感谢!

数据

import pandas as pd
df1 = pd.DataFrame(data={'id': [1,2,3,4,5,6,7,8,9,10], 
                         'a': [1,1,2,2,2,1,1,2,1,1], 
                         'b': [1,2,3,3,3,2,1,2,3,1], 
                         'c': [1,2,2,1,1,1,1,2,1,2],
                         'd': [1,1,2,2,1,1,1,1,1,2],
                        })

d1={1: 'right', 2: 'left'} 
d2={1: '10', 2: '30', 3: '20'} 
d3={1: 'green', 2: 'red'} 
d4={1: 'yes', 2: 'no'} 

df1['a']=df1['a'].map(d1).fillna('Other')
df1['b']=df1['b'].map(d2).fillna('Other')
df1['c']=df1['c'].map(d3).fillna('Other')
df1['d']=df1['d'].map(d4).fillna('Other')

组合


pd.crosstab(df1.a, df1.b)
pd.crosstab(df1.a, df1.c)
pd.crosstab(df1.a, df1.d)
pd.crosstab(df1.b, df1.c)
pd.crosstab(df1.b, df1.d)
pd.crosstab(df1.c, df1.d)


pd.crosstab(df1.a, [df1.b, df1.c])
pd.crosstab(df1.a, [df1.b, df1.d])
pd.crosstab(df1.a, [df1.c, df1.d])

pd.crosstab(df1.a, [df1.b, df1.c, df1.d])

我目前所拥有的

def cross_tab(data_frame, id_col):
    col_names=['b','c','d']
    datasets = {}
    for i in col_names:
        datasets['crosstab_{}'.format(i)] = pd.crosstab(data_frame[id_col], data_frame[i])
    return datasets
cross_tab(df1, 'a')

编辑

略微编辑的请求现在与交叉表分开 - 根据表是否包含特定值来拆分输出,在这种情况下,值为 100 的 dfs (a) 应存储在一个单独的列表中,其余部分 (b c)

数据

import pandas as pd
import numpy as np

df1 = pd.DataFrame(data={ 
                         'a': [1,1,1,1], 
                         'b': [1,1,2,1], 
                         'c': [1,2,2,1]
                        })

d1={0: 'right', 1: 'left'} 
d2={1: 'yes', 2: 'no'} 
d3={1: 'up', 2: 'down', 3: 'sideways'} 
#d4={1: 'yes', 2: 'no'} 

df1['a']=df1['a'].map(d1).fillna('Other')
df1['b']=df1['b'].map(d2).fillna('Other')
df1['c']=df1['c'].map(d3).fillna('Other')

命令已解决(我认为)

def split_cross_tabs(dataframe, cols, contain_val):
    datasets = defaultdict(dict)
    for x in df1:
        p = df1[x].value_counts(normalize=True)*100
        datasets[
            'y' if p.eq(contain_val).any().any() else'n']['crosstab_{}'.format(x)] = p
    return datasets  

输出

defaultdict(dict,
            {'y': {'crosstab_a': left    100.0
              Name: a, dtype: float64},
             'n': {'crosstab_b': yes    75.0
              no     25.0
              Name: b, dtype: float64,
              'crosstab_c': down    50.0
              up      50.0
              Name: c, dtype: float64}})

【问题讨论】:

    标签: python pandas loops combinations


    【解决方案1】:

    尝试将itertools recipe 用于powerset 并修改为仅保留长度为2 或更大的组合:

    from itertools import chain, combinations
    
    
    def all_cross_tabs(dataframe, cols):
        datasets = {}
        for s in chain.from_iterable(
                combinations(cols, r) for r in range(2, len(cols) + 1)
        ):
            datasets[f'crosstab_{"_".join(s)}'] = pd.crosstab(
                dataframe[s[0]],
                [dataframe[c] for c in s[1:]]
            )
        return datasets
    

    示例:

    d = all_cross_tabs(df1, ['a', 'b', 'c', 'd'])
    

    d.keys():

    dict_keys(['crosstab_a_b', 'crosstab_a_c', 'crosstab_a_d', 'crosstab_b_c',
               'crosstab_b_d', 'crosstab_c_d', 'crosstab_a_b_c', 'crosstab_a_b_d',
               'crosstab_a_c_d', 'crosstab_b_c_d', 'crosstab_a_b_c_d'])
    

    d['crosstab_a_b']:

    b      10  20  30
    a                
    left    0   3   1
    right   3   1   2
    

    d['crosstab_a_b_c']:

    b        10        20        30    
    c     green red green red green red
    a                                  
    left      0   0     2   1     0   1
    right     2   1     1   0     1   1
    

    d['crosstab_a_b_c_d']

    b        10        20            30    
    c     green red green     red green red
    d       yes  no    no yes  no   yes yes
    a                                      
    left      0   0     1   1   1     0   1
    right     2   1     0   1   0     1   1
    

    编辑:根据contain_val分成两部分

    def split_cross_tabs(dataframe, cols, contain_val):
        datasets = defaultdict(dict)
        for s in chain.from_iterable(
                combinations(cols, r) for r in range(2, len(cols) + 1)
        ):
            ct_df = pd.crosstab(
                dataframe[s[0]],
                [dataframe[c] for c in s[1:]]
            )
            datasets[
                'y' if ct_df.eq(contain_val).any().any() else 'n'
            ][f'crosstab_{"_".join(s)}'] = ct_df
        return datasets
    
    
    d = split_cross_tabs(df1, ['a', 'b', 'c', 'd'], 3)
    

    d.keys():

    dict_keys(['y', 'n'])
    

    list(map(lambda a: a.keys(), d.values())):

    [dict_keys(['crosstab_a_b', 'crosstab_b_c', 'crosstab_b_d']),
     dict_keys(['crosstab_a_c', 'crosstab_a_d', 'crosstab_c_d', 'crosstab_a_b_c',
                'crosstab_a_b_d', 'crosstab_a_c_d', 'crosstab_b_c_d',
                'crosstab_a_b_c_d'])]
    

    【讨论】:

    • 非常感谢,非常感谢。有没有办法也可以创建两个单独的输出列表 - 因此为包含值“3”的数据帧和不包含值的数据帧单独输出。这有意义吗?
    • 仔细检查编辑,看看我是否理解你,我把它们放在像{'y':{}, 'n':{}}这样的结构中,其中'y'是包含3的那些,'n'是那些不包含的包含 3.
    • 这也非常有用。我想知道我是否可以在更早的步骤中完成它 - 在制表之前。我在原始帖子中包含了一个编辑,其中包含新数据和我可能运行的命令示例 - 根据它们是否包含值 100 来拆分(列表)输出的数据帧。非常感谢,您的建议对我非常有用
    • 啊我想我用这个解决了我自己的问题
    猜你喜欢
    • 1970-01-01
    • 2021-06-11
    • 2018-03-02
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多