In [1]:
# https://github.com/fnielsen/everything
from everything import *

In [2]:
# Read dataframe with features for companies
filename = expanduser('~/workspace/cvrminer/virksomheder-features.csv')
df = read_csv(filename, encoding='utf-8', index_col=0)

In [3]:
# Feature names
df.columns


Out[3]:
Index([u'antal_penheder', u'branche_ansvarskode', u'nyeste_antal_ansatte',
       u'nyeste_virksomhedsform', u'reklamebeskyttet', u'sammensat_status',
       u'nyeste_statuskode', u'stiftelsesaar'],
      dtype='object')

In [4]:
# Functions for conversion to numerical dataframes
def to_dummies(df, column):
    datatype = df[column].dtypes
    if datatype in [int64, float64]:
        return df[[column]]
    elif datatype == bool:
        return df[[column]].astype(int)
    elif datatype == 'object':
        df_column = df[column].str.get_dummies()
        df_column.columns = [column + ":" + col for col in df_column.columns]
        return df_column
    else:
        raise ValueError('Unrecognized datatype for column {}'.format(column))

        
def dataframe_to_numerical(df):
    df_numerical = DataFrame(index=df.index)
    for column in df.columns:
        print(column)
        df_numerical = df_numerical.join(to_dummies(df, column))
    return df_numerical

In [5]:
# Numerical dataframe
dfn = dataframe_to_numerical(df)
dfn.shape


antal_penheder
branche_ansvarskode
nyeste_antal_ansatte
nyeste_virksomhedsform
reklamebeskyttet
sammensat_status
nyeste_statuskode
stiftelsesaar
Out[5]:
(1529578, 86)

In [6]:
# Preprocessing
imputer = Imputer()
scaler = StandardScaler(with_mean=False)
dfni = DataFrame(scaler.fit_transform(imputer.fit_transform(dfn)), columns=dfn.columns, index=dfn.index)

In [7]:
df.nyeste_statuskode.value_counts()


Out[7]:
None    1470472
3         37049
1         19948
5          1351
2           217
4           210
6           175
9           115
8            38
7             3
Name: nyeste_statuskode, dtype: int64

In [8]:
df.sammensat_status.value_counts()


Out[8]:
Ophørt                             570763
Aktiv                              437184
NORMAL                             272911
OPLØSTEFTERKONKURS                  66128
TVANGSOPLØST                        58405
OPLØSTEFTERERKLÆRING                39246
OPLØSTEFTERFRIVILLIGLIKVIDATION     36951
OPLØSTEFTERFUSION                   20581
UNDERKONKURS                         8182
SLETTET                              7570
OPLØSTEFTERSPALTNING                 6467
UNDERTVANGSOPLØSNING                 2892
UNDERFRIVILLIGLIKVIDATION            1668
Fremtid                               460
UNDERREASSUMERING                      67
slettet                                36
UDENRETSVIRKNING                       30
UNDERREKONSTRUKTION                    11
AKTIV                                   8
OPLØST                                  6
Slettet                                 4
UNDERREASUMMERING                       3
SLETTES                                 2
OPLØSTEFTERTVANGSOPLØSNING              1
UNDERREASUMMATION                       1
UNDERREASSUMMERING                      1
Name: sammensat_status, dtype: int64

In [9]:
pd.crosstab(df.sammensat_status, df.nyeste_statuskode)


Out[9]:
nyeste_statuskode 1 2 3 4 5 6 7 8 9 None
sammensat_status
AKTIV 0 0 0 0 0 0 0 0 0 8
Aktiv 179 31 447 12 39 5 0 4 13 436454
Fremtid 0 0 0 0 0 0 0 0 0 460
NORMAL 16 24 5 0 1 0 0 0 1 272864
OPLØST 0 0 0 0 0 0 0 0 0 6
OPLØSTEFTERERKLÆRING 4 3 0 0 0 0 0 0 2 39237
OPLØSTEFTERFRIVILLIGLIKVIDATION 5 6 0 1 6 0 0 0 3 36930
OPLØSTEFTERFUSION 13 5 0 0 1 0 0 0 2 20560
OPLØSTEFTERKONKURS 11646 9 34348 40 630 78 0 3 18 19356
OPLØSTEFTERSPALTNING 0 0 1 0 0 0 0 0 0 6466
OPLØSTEFTERTVANGSOPLØSNING 0 0 0 0 0 0 0 0 0 1
Ophørt 2429 92 289 5 43 7 1 31 68 567798
SLETTES 0 0 0 0 0 0 0 0 0 2
SLETTET 4 0 5 2 1 0 0 0 0 7558
Slettet 0 0 0 0 0 0 0 0 0 4
TVANGSOPLØST 189 46 205 1 12 2 0 0 8 57942
UDENRETSVIRKNING 0 0 0 0 0 0 0 0 0 30
UNDERFRIVILLIGLIKVIDATION 3 0 0 0 0 0 0 0 0 1665
UNDERKONKURS 5317 1 1741 145 615 82 1 0 0 280
UNDERREASSUMERING 9 0 2 0 0 0 0 0 0 56
UNDERREASSUMMERING 0 0 0 0 0 0 0 0 0 1
UNDERREASUMMATION 0 0 0 0 0 0 0 0 0 1
UNDERREASUMMERING 0 0 0 0 0 0 0 0 0 3
UNDERREKONSTRUKTION 1 0 0 1 0 0 1 0 0 8
UNDERTVANGSOPLØSNING 133 0 6 3 3 1 0 0 0 2746
slettet 0 0 0 0 0 0 0 0 0 36

In [10]:
indices = df.sammensat_status.isin(['Aktiv', u'OPLØSTEFTERKONKURS']).values
dfs = df.ix[indices, :].copy()
dfs.shape


Out[10]:
(503312, 8)

In [11]:
dfs['konkurs'] = (dfs.sammensat_status == u'OPLØSTEFTERKONKURS').astype(int)

In [12]:
def transform_year(year):
    return year - 2000


results = smf.glm(('konkurs ~ np.log(antal_penheder+1) + C(nyeste_antal_ansatte) + ' 
                   # nyeste_virksomhedsform + nyeste_statuskode + 
                   'branche_ansvarskode + reklamebeskyttet + transform_year(stiftelsesaar)'),
                  data=dfs, family=sm.families.Binomial()).fit()

In [13]:
print(results.summary())


                 Generalized Linear Model Regression Results                  
==============================================================================
Dep. Variable:                konkurs   No. Observations:               268243
Model:                            GLM   Df Residuals:                   268222
Model Family:                Binomial   Df Model:                           20
Link Function:                  logit   Scale:                             1.0
Method:                          IRLS   Log-Likelihood:                -75790.
Date:                Thu, 18 Aug 2016   Deviance:                   1.5158e+05
Time:                        22:30:48   Pearson chi2:                 2.97e+05
No. Iterations:                    26                                         
=====================================================================================================
                                        coef    std err          z      P>|z|      [95.0% Conf. Int.]
-----------------------------------------------------------------------------------------------------
Intercept                            -0.1821      0.187     -0.976      0.329        -0.548     0.184
C(nyeste_antal_ansatte)[T.1.0]        1.3965      0.019     71.879      0.000         1.358     1.435
C(nyeste_antal_ansatte)[T.2.0]        1.4391      0.019     76.948      0.000         1.402     1.476
C(nyeste_antal_ansatte)[T.5.0]        1.6605      0.025     67.751      0.000         1.612     1.709
C(nyeste_antal_ansatte)[T.10.0]       1.9545      0.032     62.028      0.000         1.893     2.016
C(nyeste_antal_ansatte)[T.20.0]       2.1077      0.043     49.589      0.000         2.024     2.191
C(nyeste_antal_ansatte)[T.50.0]       1.8773      0.093     20.237      0.000         1.696     2.059
C(nyeste_antal_ansatte)[T.100.0]      1.2759      0.157      8.126      0.000         0.968     1.584
C(nyeste_antal_ansatte)[T.200.0]      1.4266      0.274      5.206      0.000         0.889     1.964
C(nyeste_antal_ansatte)[T.500.0]      1.0133      0.752      1.347      0.178        -0.461     2.488
C(nyeste_antal_ansatte)[T.1000.0]     0.7364      1.051      0.701      0.484        -1.324     2.796
branche_ansvarskode[T.15]            -4.5699      1.034     -4.421      0.000        -6.596    -2.544
branche_ansvarskode[T.65]             0.4971      0.209      2.381      0.017         0.088     0.906
branche_ansvarskode[T.75]           -26.7808   3.85e+04     -0.001      0.999     -7.55e+04  7.54e+04
branche_ansvarskode[T.96]            30.5924   5.87e+05   5.21e-05      1.000     -1.15e+06  1.15e+06
branche_ansvarskode[T.97]             0.5545      0.614      0.903      0.366        -0.649     1.758
branche_ansvarskode[T.99]             0.2416      0.542      0.446      0.656        -0.820     1.303
branche_ansvarskode[T.None]          -1.9593      0.180    -10.896      0.000        -2.312    -1.607
reklamebeskyttet[T.True]             -2.6928      0.051    -52.787      0.000        -2.793    -2.593
np.log(antal_penheder + 1)           -0.5775      0.072     -8.058      0.000        -0.718    -0.437
transform_year(stiftelsesaar)         0.0498      0.001     74.561      0.000         0.048     0.051
=====================================================================================================

In [14]:
actives = dfs.sammensat_status.isin(['Aktiv']).values
y_est = results.predict(exog=dfs.ix[actives, :])
indices = argsort(-y_est)

In [15]:
# dfs.ix[actives, :].iloc[indices, :].head(100)

In [ ]: