Kaggle competition: Conway's Reverse Game of Life 2020
<SOS> metric: PostProcessorKernel Kaggle data source: conways-reverse-game-of-life-2020<concatenate>
import time
import pandas as pd
import torch
useful.append('Fare' )<feature_engineering>
torch.backends.cudnn.benchmark = True
torch.backends.cudnn.deterministic = False
df['small_family'] = df['family_size'].apply(lambda size: 1 if size<=4 else 0)
 df['big_family'] = df['family_size'].apply(lambda size: 1 if size>=7 else 0)
 df['no_family'] = df['family_size'].apply(lambda s: 1 if s==1 else 0)
 useful.extend(['SibSp', 'Parch', 'family_size', 'small_family', 'big_family', 'no_family'] )<categorify>
N = 25
device = 'cuda'
TEST_CSV = '.. /input/conways-reverse-game-of-life-2020/test.csv'
OUTPUT_CSV = 'submission.csv'
df['male'] = df['Sex'].map({'male': 1, 'female': 0})
 useful.append('male' )<categorify>
cv = torch.nn.Conv2d(1, 1, kernel_size=3, padding=1, padding_mode='circular', bias=False)
 cv.requires_grad=False
cv.weight = torch.nn.Parameter(
 torch.tensor(
 [[[[ 1., 1., 1.],
[ 1., 0., 1.],
[ 1., 1., 1.]]]],
device=device,
dtype=torch.float16 
),
requires_grad=False, 
)
 @torch.jit.script
def forward(grid, delta: int):
N=25
g = grid.reshape(-1, 1, N, N)
 for _ in torch.arange(delta):
g = g.to(torch.float16)
 neighbor_sum = cv(g)
 g =(( neighbor_sum == 3)|(( g == 1)&(neighbor_sum == 2)))
 return g.reshape(-1, N, N )
df = pd.concat([df, pd.get_dummies(df['Embarked'], prefix='embarked')], axis=1)
 useful.extend(['embarked_{}'.format(x)for x in ['C', 'S', 'Q']])
 df.sample(5 )<concatenate>
@torch.jit.script
def random_parents(n_parents: int, device: str):
N = 25
RANDOM_ALIVE =.2
return torch.rand(( n_parents, N, N), device=device)>(1-RANDOM_ALIVE )
useful.append('Pclass' )<categorify>
@torch.jit.script
def loss(input, target):
return torch.sum(input ^ target, dim=(-1,-2))
df = pd.concat([df, pd.get_dummies(df['cabin_letter'], prefix='deck')], axis=1)
 letters = df['cabin_letter'].unique()
useful.extend(['deck_{}'.format(x)for x in letters] )<sort_values>
@torch.jit.script
def select_best(parents, delta: int, target, n_best: int):
scores = loss(forward(parents, delta), target)
 best_values, best_indices = torch.topk(scores, n_best, dim=0, largest=False, sorted=True)
 new_parents = parents[best_indices,...]
return new_parents, best_values[0], new_parents[0,...]
ticket_count = df[['Ticket', 'Name']].groupby('Ticket' ).count().rename(columns={'Name':'count'} ).sort_values(by='count', ascending=False)
 ticket_count.head()<filter>
@torch.jit.script
def random_combine(parents, n_offsprings: int, device: str, pre_masks):
N = 25
dads = torch.randint(low=0, high=parents.shape[0], size=(n_offsprings,),
device=device, dtype=torch.long)
 dads = parents[dads,...]
moms = torch.randint(low=0, high=parents.shape[0], size=(n_offsprings,),
device=device, dtype=torch.long)
 moms = parents[moms,...]
masks = pre_masks[torch.randint(low=0, high=pre_masks.shape[0], size=(n_offsprings,),
device=device, dtype=torch.long)]
return torch.where(masks, dads, moms )
df[df['Ticket']=='CA.2343']<filter>
def precomputes_masks() :
N = 25
BLOCK_SIZE = 17
block = torch.nn.Conv2d(1, 1, kernel_size=BLOCK_SIZE, padding=BLOCK_SIZE//2,
padding_mode='circular', bias=False)
 block.requires_grad=False
block.weight = torch.nn.Parameter(
 torch.ones(( 1, 1, BLOCK_SIZE, BLOCK_SIZE),
device=device,
dtype=torch.float16 
),
requires_grad=False, 
)
 masks = torch.zeros(( N * N, 1, N, N), device=device, dtype=torch.float16)
 for x in range(N):
for y in range(N):
masks[x * N + y, 0, x, y] = 1.
 masks = block(masks)
 return masks[:, 0,...] >.5
df[df['Ticket']=='1601']<feature_engineering>
@torch.jit.script
def mutate(parents, device: str):
MUTATION =.0016
mutations = torch.rand(parents.shape, device=device)< MUTATION
return parents ^ mutations
df['ticket_owners'] = df['Ticket'].apply(lambda x: ticket_count.loc[x])
 df['shared_fare'] = df['Fare'] / df['ticket_owners']
df['alone'] = df[['ticket_owners','no_family']].apply(lambda row: 1 if row.ticket_owners==1 and row.no_family==1 else 0 , axis=1)
 useful.extend(['ticket_owners', 'shared_fare', 'alone'] )<feature_engineering>
@torch.jit.script
def optimize_one_puzzle(delta: int, data, device: str, pre_masks):
N = 25
N_GENERATION = 30
P = 4_500
N_BEST = P // 30
N_ELITES = 8
best_score = torch.tensor([N*N], device=device)
 best = torch.zeros(( N,N), device=device ).to(torch.bool)
 parents = random_parents(P, device)
 elites = torch.empty(( 1, N, N), dtype=torch.bool, device=device)
 elites[0,...] = data
for i in range(N_GENERATION):
parents = random_combine(parents, P, device, pre_masks)
 parents = mutate(parents, device)
 parents[:N_ELITES,...] = elites
parents, best_score, best = select_best(parents, delta, data, N_BEST)
 elites = parents[:N_ELITES,...]
if best_score == 0:
break
return best_score, best
older_age = df[['Ticket', 'Age']].groupby('Ticket' ).max()
df['older_relative_age'] = df['Ticket'].apply(lambda ticket: older_age.loc[ticket])
 useful.extend(['older_relative_age'] )<feature_engineering>
@torch.jit.script
def optimize_all_puzzles(deltas, df, device: str, pre_masks):
sub = df.clone()
for n in torch.arange(df.shape[0]):
delta = deltas[n]
data = df[n,...]
_, sub[n,...] = optimize_one_puzzle(delta, data, device, pre_masks)
 return sub
def ticket_type(t):
if re.match('^\d+$', t):
return 'len' + str(len(t))
else:
return re.sub('[^A-Z]', '', t)
 df['ticket_type'] = df['Ticket'].apply(ticket_type)
 df[['ticket_type', 'Survived']].groupby(
 'ticket_type' ).agg({'Survived': ['mean', 'std','count']} ).sort_values(( 'Survived','count'), ascending=False )<categorify>
df = pd.read_csv(TEST_CSV, index_col='id' )
def useful_ticket_type(ticket_type):
useful_types = ['A', 'SOTONOQ', 'WC']
if ticket_type in useful_types:
return ticket_type
else:
return 'other'
df['useful_ticket_type'] = df['ticket_type'].apply(useful_ticket_type)
 df = pd.concat(
 [df, pd.get_dummies(df['useful_ticket_type'], prefix='ticket_type')], axis=1)
 letters = df['useful_ticket_type'].unique()
useful.extend(['ticket_type_{}'.format(x)for x in letters])
 df.sample(10 )<feature_engineering>
submission = df.copy()
submission.drop(['delta'], inplace=True, axis=1 )
df['name_length_short'] = df['name_length'].apply(lambda s: 1 if s <= 35 else 0)
 df['name_length_mid'] = df['name_length'].apply(lambda s: 1 if 35 < s <=58 else 0)
 df['name_length_long'] = df['name_length'].apply(lambda s: 1 if s > 58 else 0)
 useful.extend(['name_length', 'name_length_short', 'name_length_mid', 'name_length_long'] )<feature_engineering>
indexes = df.index
deltas = torch.from_numpy(df.delta.values ).to(device)
 df = torch.BoolTensor(df.values[:, 1:].reshape(( -1, N, N)) ).to(device )
df['lang'] = df['Name'].apply(lambda n: langid.classify(n)[0])
 df[['Name','lang']].sample(10 )<groupby>
start_time = time.time()
pre_masks = precomputes_masks()
sub = optimize_all_puzzles(deltas, df, device, pre_masks)
 print(f'Processed {sub.shape[0]:,} puzzles in {time.time() - start_time:.2f} seconds 🔥🔥🔥' )
lang_count = df[['lang','Name']].groupby('lang' ).count().rename(columns={'Name':'count'})
 lang_class = df[['lang','Pclass']].groupby('lang' ).mean()
lang_survived = df[['lang','Survived']].groupby('lang' ).mean()
pd.concat([lang_count, lang_class, lang_survived], axis=1 ).sort_values(by='count', ascending=False ).head(15 )<feature_engineering>
submission.rename(columns={f'stop_{x}': f'start_{x}' for x in range(N*N)}, inplace=True)
 submission.iloc[:sub.shape[0], :] = sub.reshape(( -1, N*N)).cpu().numpy().astype(int)
 submission.to_csv(OUTPUT_CSV )
language_groups = {
'uk':('cy', 'en'),
'germanic':('da', 'de', 'nl'),
'latin':('es', 'fr', 'it', 'la', 'pt', 'br', 'ro'),
'african':('af', 'rw', 'xh'),
'asian':('id', 'tl', 'tr')
 }
language_map = { y:x for x in language_groups for y in language_groups[x]}
df['lang_group'] = df['lang'].apply(lambda l: language_map[l] if l in language_map else 'other')
 survived_avg_per_group = df[['lang_group','Survived']].groupby('lang_group' ).mean()
survived_std_per_group = df[['lang_group','Survived']].groupby('lang_group' ).std().rename(columns={'Survived':'std'})
 pd.concat([survived_avg_per_group, survived_std_per_group], axis=1 )<categorify>
def leaderboard_score(deltas, df, sub, device: str):
result = torch.empty(sub.shape[0], device=device, dtype=torch.long)
 for delta in range(1, 6):
start = sub[deltas == delta]
end = df[deltas == delta]
result[deltas == delta] = loss(forward(start, delta), end)
 print('Leaderboard score:', torch.sum(result ).item() /(result.shape[0]*N*N))
df = pd.concat([df, pd.get_dummies(df['lang_group'], prefix='lang_group')], axis=1)
 langs = df['lang_group'].unique()
useful.extend(['lang_group_{}'.format(x)for x in langs] )<feature_engineering>
leaderboard_score(deltas, df, sub, device )