<jupyter_start><jupyter_text>Data Wrangling: We Rate Dogs Twitter account<jupyter_code># Import 
import numpy as np
import pandas as pd
import requests
import tweepy
import json
import time
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
%matplotlib inline
import seaborn as sb<jupyter_output><empty_output><jupyter_text>Table of contentsData gatheringData assessmentData cleaningSavingAnalysis and visualisation  Data gathering In the first part of this project, the required data will be gathered from different sources.<jupyter_code># Create a data frame from the provided .csv-file
df_archive = pd.read_csv('twitter-archive-enhanced.csv')
# Download the provided .tsv-file programmatically
r = requests.get('https://d17h27t6h515a5.cloudfront.net/topher/2017/August/599fd2ad_image-predictions/image-predictions.tsv')
# Check success of request
r.status_code
# Write the downloaded object into a file
with open('image-predictions.tsv', mode = 'wb') as file:
    file.write(r.content)
# Create a data frame
df_images = pd.read_csv('image-predictions.tsv', sep='\t')
# Prepare for using the Twitter API
consumer_key = 'CONSUMER KEY'
consumer_secret = 'CONSUMER SECRET'
access_token = 'ACCESS TOKEN'
access_secret = 'ACCESS SECRET'

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_secret)

api = tweepy.API(auth, wait_on_rate_limit = True, wait_on_rate_limit_notify = True)
# Query json data for each tweet ID in the Twitter archive of WeRateDogs
missing_ids = [] # initialise list
count = 1
start = time.time()

with open('tweet_json.txt', 'w') as outfile:
    for i in df_archive.tweet_id: # get each tweet ID
        try:
            # write the json data for each ID into a text file
            tweet = api.get_status(i, tweet_mode = 'extended')
            json.dump(tweet._json, outfile)
            outfile.write('\n') # add new line
        except tweepy.TweepError: 
            # catch error and write missing IDs into list
            missing_ids.append(i)
        print(count, ': Tweet ID ', i)
        count += 1
        
end = time.time()
print('Elapsed time: ', (end - start)/60, ' minutes')
# Read text file with json data line by line
json_list = []
with open('tweet_json.txt') as file:
    for line in file:
        json_list.append(json.loads(line))
# Get tweet ids that have corresponding json data 
json_ids = np.array(df_archive.tweet_id[df_archive['tweet_id'].isin(missing_ids) == False])
# Write a data frame with the retweet and favorite counts
df_list = []
favorite_count = {}
for i in range(len(json_list)):
    df_list.append({'tweet_id': json_ids[i],
                    'retweet_count': json_list[i]['retweet_count'],
                    'favorite_count': json_list[i]['favorite_count']})
df_popularity = pd.DataFrame(df_list)<jupyter_output><empty_output><jupyter_text>Data assessmentIn this part of the project, I will inspect the data to identify quality and tidiness issues.<jupyter_code>df_archive.head()
df_archive.info()
df_archive.sample(5)
df_archive.name.value_counts()
df_archive.name.value_counts().sample(20)
# print the text of all tweet IDs with non-names to identify the errors
# get index of non-names
ind = df_archive.name.str.extract('(^[a-z]+$)').dropna().index
# print index and text for non-names
for i in ind:
    print(i, '--', df_archive.text[i])
df_archive.doggo.value_counts()
df_archive.floofer.value_counts()
df_archive.pupper.value_counts()
df_archive.puppo.value_counts()
df_archive.rating_numerator.value_counts()
# Print the text of all tweet IDs with unusual numerators to identify the errors
# Get unusual values
vals = df_archive.rating_numerator.value_counts()[df_archive.rating_numerator.value_counts() <=2].index
# Filter for unusual values
mask = df_archive.rating_numerator.isin(vals)
# Print index and text of unusual values
for i in df_archive.loc[mask, 'text'].index:
    print(i, '--', df_archive.text[i])
df_archive.rating_denominator.value_counts()
# Print the text of all tweet IDs with unusual denominators to identify the errors
# Get unusual values
vals = df_archive.rating_denominator.value_counts()[df_archive.rating_denominator.value_counts() <=3].index
# Filter for unusual values
mask = df_archive.rating_denominator.isin(vals)
# Print index and text of unusual values
for i in df_archive.loc[mask, 'text'].index:
    print(i, '--', df_archive.text[i])
df_images.head()
df_images.sample(5)
df_images.info()
df_popularity.head()
df_popularity.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 2331 entries, 0 to 2330
Data columns (total 3 columns):
 #   Column          Non-Null Count  Dtype
---  ------          --------------  -----
 0   tweet_id        2331 non-null   int64
 1   retweet_count   2331 non-null   int64
 2   favorite_count  2331 non-null   int64
dtypes: int64(3)
memory usage: 54.8 KB<jupyter_text>The following issues were found after executing the code above: Quality issues `df_archive`1. `df_archive` has more rows than `df_images`, so there are some tweets with no images (project requirements are to use only tweets with images)2. Missing values in dog stage variables and `name` are marked as 'None' instead of NaN3. `tweet_id`, `in_reply_to_status_id`, `in_reply_to_user_id`, `retweeted_status_id` and `retweeted_status_user_id` are floats instead of strings4. Data frame contains retweets and replies but should only contain original tweets5. Some names are wrong in `name`    1. It seems that all incorrect name entries are spelt with lowercase letters.     2. Checking the text of these cases reveals that the expressions "named..." and "name is..." were not considered when extracting the names from the text    3. Index no. 369 should have the name "Grace"6. Some values in `rating_numerator` and `rating_denominator` appear to be wrong    1. index of wrong values: [55, 313, 340, 342, 516, 763, 1068, 1165, 1202, 1662, 1712, 2335]    2. correct values: [13/10, 13/10, 9.75/10, NaN, NaN, NaN, 11.27/10, 14/10, 13/10, 11/10, NaN, 11.26/10, 9/10]7. `timestamp` and `retweeted_status_timestamp` columns are strings instead of dates. This will be ignored for two reasons, though:    1. I do not intend to analyse any time based information    2. When storing the data frame into a .csv-file, the date format will be lost again `df_images`8. Some images do not show dogs9. There are three possible dog breeds for each image instead of one10. Names of dog breeds are not formated consistently11. `tweet_id` is int instead of string `df_popularity`12. Fewer number of tweet IDs than in the other data frames. Instead of trimming the other data frames, these will be accepted as missing values. No action required.13. `tweet_id` is int instead of string Tidiness issues14. `df_archive`: Dog stage variable is written as 4 columns but it should be one column15. `df_archive`: Rating is separated into two columns but should be one variable in one column16. `df_popularity`: Should not be a separate data frame but should be written into `df_archive`17. `df_images`: The selected dog breed and jpg url should be written into `df_archive`  Data cleaning<jupyter_code># Make backup copies of all data frames
df_archive_raw = df_archive.copy()
df_images_raw = df_images.copy()
df_popularity_raw = df_popularity.copy()<jupyter_output><empty_output><jupyter_text>Issues 8 & 9: Some images do not show dogs in `df_images` (this needs to be fixed before I can tackle Issue 1) & there are three possible dog breeds for each image instead of one  DefineExclude rows where `p1`, `p2` and `p3` are not a dog breed and define the "true breed" for each image by picking the breed prediction with the highest confidence.  Code<jupyter_code># Select only rows with at least one recognised dog breed
df_images = df_images[((df_images.p1_dog == True) | (df_images.p2_dog == True) | (df_images.p3_dog == True))] 
# Choose dog breed with biggest confidence in each row
for i in df_images.index:
    if (df_images.p1_conf[i] > df_images.p2_conf[i]) & (df_images.p1_dog[i] == True):
        df_images.loc[i,'selected_breed'] = df_images.loc[i,'p1']
    elif (df_images.p2_conf[i] > df_images.p3_conf[i]) & (df_images.p2_dog[i] == True):
        df_images.loc[i,'selected_breed'] = df_images.loc[i,'p2']
    else:
        df_images.loc[i,'selected_breed'] = df_images.loc[i,'p3']<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check if selected breed is a dog breed and has the highest confidence
df_images.sample(10)<jupyter_output><empty_output><jupyter_text>Issue 1: `df_archive` has more rows than `df_images`  DefineSelect only those tweet IDs in `df_archive` that are in `df_images`  Code<jupyter_code># Get tweet ids in df_images and filter df_archive
tweet_list = df_images.tweet_id.values
df_archive = df_archive[df_archive['tweet_id'].isin(tweet_list)]<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check if the two data frames have the same length
len(df_archive) == len(df_images)<jupyter_output><empty_output><jupyter_text>Issue 2: Missing values in dog stage variables and `name` are marked as 'None' instead of NaN in `df_archive`  DefineReplace 'None' with NaN  Code<jupyter_code>df_archive = df_archive.replace('None', np.nan)<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># make sure that 'None' is no longer a value
df_archive.doggo.value_counts()
# Make sure that 'None' is no longer a value
df_archive.floofer.value_counts()
# Make sure that 'None' is no longer a value
df_archive.pupper.value_counts()
# Make sure that 'None' is no longer a value
df_archive.puppo.value_counts()<jupyter_output><empty_output><jupyter_text>Issues 3, 11 & 13: `tweet_id`, `in_reply_to_status_id`, `in_reply_to_user_id`, `retweeted_status_id` and `retweeted_status_user_id` have wrong data types in `df_archive`, `df_images` and `df_popularity`  DefineChange format `in_reply_to_status_id`, `in_reply_to_user_id`, `retweeted_status_id` and `retweeted_status_user_id` to int  Code<jupyter_code># Change data format
df_archive.tweet_id = df_archive.tweet_id.astype('object')
df_archive.in_reply_to_status_id = df_archive.in_reply_to_status_id.astype('object')
df_archive.in_reply_to_user_id = df_archive.in_reply_to_user_id.astype('object')
df_archive.retweeted_status_id = df_archive.retweeted_status_id.astype('object')
df_archive.retweeted_status_user_id = df_archive.retweeted_status_user_id.astype('object')

df_images.tweet_id = df_images.tweet_id.astype('object')

df_popularity.tweet_id = df_popularity.tweet_id.astype('object')<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check data type
df_archive.info()
# Check data type
df_images.info()
# Check data type
df_popularity.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 2331 entries, 0 to 2330
Data columns (total 3 columns):
 #   Column          Non-Null Count  Dtype 
---  ------          --------------  ----- 
 0   tweet_id        2331 non-null   object
 1   retweet_count   2331 non-null   int64 
 2   favorite_count  2331 non-null   int64 
dtypes: int64(2), object(1)
memory usage: 54.8+ KB<jupyter_text>Issue 4: `df_archive` contains retweets and replies  DefineFilter `df_archive` to keep only those rows where `in_reply_to_status_id` and `retweeted_status_id` are NaNs. Then drop these columns because they are of no use.  Code (filter)<jupyter_code># Include only rows with no retweets and replies
df_archive = df_archive[(df_archive.in_reply_to_status_id.isnull()) & (df_archive.retweeted_status_id.isnull())]<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check data type (before dropping)
df_archive.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
Int64Index: 1666 entries, 1 to 2355
Data columns (total 17 columns):
 #   Column                      Non-Null Count  Dtype 
---  ------                      --------------  ----- 
 0   tweet_id                    1666 non-null   object
 1   in_reply_to_status_id       0 non-null      object
 2   in_reply_to_user_id         0 non-null      object
 3   timestamp                   1666 non-null   object
 4   source                      1666 non-null   object
 5   text                        1666 non-null   object
 6   retweeted_status_id         0 non-null      object
 7   retweeted_status_user_id    0 non-null      object
 8   retweeted_status_timestamp  0 non-null      object
 9   expanded_urls               1666 non-null   object
 10  rating_numerator            1666 non-null   int64 
 11  rating_denominator          1666 non-null   int64 
 12  name                        1266 non-null   object
 13  doggo                       63 non-null     obje[...]<jupyter_text>Code (drop unused columns)<jupyter_code># Drop unused columns
df_archive = df_archive.drop(['in_reply_to_status_id','in_reply_to_user_id','retweeted_status_id','retweeted_status_user_id','retweeted_status_timestamp'], axis = 1)<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Make sure that columns were dropped
df_archive.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
Int64Index: 1666 entries, 1 to 2355
Data columns (total 12 columns):
 #   Column              Non-Null Count  Dtype 
---  ------              --------------  ----- 
 0   tweet_id            1666 non-null   object
 1   timestamp           1666 non-null   object
 2   source              1666 non-null   object
 3   text                1666 non-null   object
 4   expanded_urls       1666 non-null   object
 5   rating_numerator    1666 non-null   int64 
 6   rating_denominator  1666 non-null   int64 
 7   name                1266 non-null   object
 8   doggo               63 non-null     object
 9   floofer             8 non-null      object
 10  pupper              173 non-null    object
 11  puppo               22 non-null     object
dtypes: int64(2), object(10)
memory usage: 169.2+ KB<jupyter_text>Issue 5: Some names are wrong in `name`  Define1. Extract and replace the names after the expressions "named..." and "name is..."2. Replace the name with index 369 with "Grace"3. Replace the remaining lowercase entries in `name` with NaNs  Code<jupyter_code># Get dataframe with non-names
ind = df_archive.name.str.extract('(^[a-z]+$)').dropna().index
df_archive_nonames = df_archive.loc[ind]
# Extract and replace names after "named..."
named = df_archive_nonames.text.str.extract('named\s([A-Z][a-z]+)[\s\.]').dropna().rename(columns={0:'name'})
df_archive.update(named)
# Extract and replace names after "name is..."
name_is = df_archive_nonames.text.str.extract('name is\s([A-Z][a-z]+)[\s\.]').dropna().rename(columns={0:'name'})
df_archive.update(name_is)
# Replace name at index 369 with "Grace"
grace = pd.Series('Grace', name='name', index=[369])
df_archive.update(grace)
# Replace the rest of the wrong names with NaNs
rest_ind = []
for i in ind:
    if i not in np.concatenate((np.array(named.index), np.array(name_is.index), [369])):
        df_archive.replace(df_archive.name.loc[i], np.nan, inplace = True)<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check entries of non-names (most of them should be NaN)
df_archive.loc[ind]['name']
# Check entries of the names extracted after "named..."
df_archive.loc[np.array(named.index)]['name']
# Check entries of the names extracted after "name is..."
df_archive.loc[np.array(name_is.index)]['name']
# Check entry at index 369
df_archive.loc[grace.index]['name']<jupyter_output><empty_output><jupyter_text>Issues 6 & 15: Some values in `rating_numerator` and `rating_denominator` appear to be wrong & rating is separated into two columns but should be one variable in one column  Define1. Calculate rating as one number and write it into one column2. Set the values with index [55, 313, 340, 342, 516, 763, 1068, 1165, 1202, 1662, 1712, 2335] to [13/10, 13/10, 9.75/10, NaN, NaN, NaN, 11.27/10, 14/10, 13/10, 11/10, NaN, 11.26/10, 9/10]3. Drop unsused columns  Code<jupyter_code># Define a series with indices and values as defined in the data assessment
new_rating_index = [55, 313, 340, 342, 516, 763, 1068, 1165, 1202, 1662, 1712, 2335]
new_rating = [13/10, 13/10, 9.75/10, np.nan, np.nan, 11.27/10, 14/10, 13/10, 11/10, np.nan, 11.26/10, 9/10]
new_rating = pd.Series(new_rating, name='rating', index=new_rating_index)
ind = []
for i in df_archive.index:
    if i in new_rating_index: # check if index is still present or was deleted in previous cleaning actions
        df_archive.loc[i, 'rating'] = new_rating[i] # change values according to new_rating
        ind.append(i) # write changed indices into list
    else:
        df_archive.loc[i, 'rating'] = df_archive.rating_numerator[i] / df_archive.rating_denominator[i] # calculate rating
# Drop unused columns
df_archive = df_archive.drop(['rating_numerator','rating_denominator'], axis = 1)<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check changed ratings changed according to new_rating
df_archive.loc[ind,'rating']
# Check new column
df_archive.sample(10)<jupyter_output><empty_output><jupyter_text>Issue 10: Names of dog breeds are not formated consistently   DefineReplace the underscore(s) in `selected_breed` and capitalise the first letters of each word  Code<jupyter_code># Replace underscores and capitalise
df_images.selected_breed = df_images.selected_breed.str.replace('_',' ').str.title()<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check new names of dog breeds
df_images.selected_breed.sample(20)<jupyter_output><empty_output><jupyter_text>Issue 14: Dog stage variable is written as 4 columns but it should be one column in `df_archive`  DefineWrite dog stages into one column and delete the unused columns  Code<jupyter_code>for line in df_archive.index: # go through each line 
    for val in df_archive.loc[line,['doggo','floofer','pupper','puppo']]: # go through each value in a line
        if val in ['doggo','floofer','pupper','puppo']:
            df_archive.loc[line,'dog_stage'] = val
# Drop unused columns
df_archive = df_archive.drop(['doggo','floofer','pupper','puppo'], axis = 1)<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check new column
df_archive.sample(10)<jupyter_output><empty_output><jupyter_text>Issue 16: `df_popularity` should not be a separate data frame but should be written into `df_archive`  DefineMerge `df_popularity` and `df_archive` into one data frame  Code<jupyter_code># Merge the two data frames and change data types of new columns to 'int'
df_archive = df_archive.merge(df_popularity, how = 'left', on = 'tweet_id')
df_archive.retweet_count = df_archive.retweet_count.astype('Int64')
df_archive.favorite_count = df_archive.favorite_count.astype('Int64')<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check new columns and their data type
df_archive.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
Int64Index: 1666 entries, 0 to 1665
Data columns (total 10 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   tweet_id        1666 non-null   object 
 1   timestamp       1666 non-null   object 
 2   source          1666 non-null   object 
 3   text            1666 non-null   object 
 4   expanded_urls   1666 non-null   object 
 5   name            1206 non-null   object 
 6   rating          1664 non-null   float64
 7   dog_stage       257 non-null    object 
 8   retweet_count   1659 non-null   Int64  
 9   favorite_count  1659 non-null   Int64  
dtypes: Int64(2), float64(1), object(7)
memory usage: 146.4+ KB<jupyter_text>Issue 17: `selected_breed` and `jpg_url` in `df_images` should be written into `df_archive`  DefineMerge the `selected_breed` and `jpg_url` columns of `df_images` and `df_archive` into one data frame  Code<jupyter_code>df_archive = df_archive.merge(df_images[['tweet_id','selected_breed','jpg_url']], how = 'left', on = 'tweet_id')<jupyter_output><empty_output><jupyter_text>Test<jupyter_code># Check new column
df_archive.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
Int64Index: 1666 entries, 0 to 1665
Data columns (total 12 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   tweet_id        1666 non-null   object 
 1   timestamp       1666 non-null   object 
 2   source          1666 non-null   object 
 3   text            1666 non-null   object 
 4   expanded_urls   1666 non-null   object 
 5   name            1206 non-null   object 
 6   rating          1664 non-null   float64
 7   dog_stage       257 non-null    object 
 8   retweet_count   1659 non-null   Int64  
 9   favorite_count  1659 non-null   Int64  
 10  selected_breed  1666 non-null   object 
 11  jpg_url         1666 non-null   object 
dtypes: Int64(2), float64(1), object(9)
memory usage: 172.5+ KB<jupyter_text>Saving<jupyter_code># Save the master data frame to a csv-file
df_archive.to_csv('twitter_archive_master.csv', index=False)<jupyter_output><empty_output><jupyter_text>Analysis and visalisation There are three questions I would like to answer:1. Which tweet was retweeted the most?2. Which dog breed was retweeted the most?3. Which dog breed received the most "likes"?<jupyter_code># Get image url of tweet with the most retweets and download file
mask = df_archive.retweet_count == df_archive.retweet_count.max()
ind_max_retweet = df_archive.text[mask].index[0]
url = df_archive.jpg_url.loc[ind_max_retweet]
r = requests.get(url)
# Write the downloaded object into a file
with open('max_retweeted_image.jpg', mode = 'wb') as file:
    file.write(r.content)
# Get image and text of tweet with the most retweets 
max_retweeted_image = mpimg.imread('max_retweeted_image.jpg')
max_retweeted_text = df_archive.text[mask].values[0]
max_retweeted_text = max_retweeted_text[:max_retweeted_text.rfind('https')] # strip off tweet url
# Plot
fig, ax = plt.subplots()
ax.imshow(max_retweeted_image);
props = dict(boxstyle='round', facecolor='skyblue', alpha=0.5)
ax.text(-800, 800, max_retweeted_text, fontsize=14, bbox=props);
plt.axis('off');
plt.title('This tweet was retweeted most often: {} times'.format(df_archive.retweet_count.max()));<jupyter_output><empty_output><jupyter_text>The above image shows the tweet text and image that was retweeted most often.<jupyter_code># Group by dog breed and get the top ten of mean retweets per breed 
top_retweeted_breeds = df_archive.groupby('selected_breed').mean().retweet_count.sort_values(axis=0,ascending=False).index[:11]
# Get data frame with top ten dog breeds 
df_top_breeds = df_archive[df_archive.selected_breed.isin(top_retweeted_breeds)]
# Plot the top ten dog breeds
sb.pointplot(x = df_top_breeds.retweet_count, y = df_top_breeds.selected_breed, 
             color = 'skyblue', order = top_retweeted_breeds, linestyles='');
plt.xticks(rotation=30);
plt.xlabel('Mean retweet count');
plt.ylabel('');
plt.title('Top ten dog breeds in terms of mean retweets');<jupyter_output><empty_output><jupyter_text>This image shows the top ten dogs in terms of mean retweets. Tweets with Bedlington Terrier dogs were retweeted most often. However, the spread of the retweet counts is quite high. Some individual tweets of the other top ten breeds were retweeted more often than the mean retweets of the Bedlington Terriers, for example the Standard Poodle or the English Springer.<jupyter_code># Group by dog breed and get the top ten of mean likes per breed 
top_favorite_breeds = df_archive.groupby('selected_breed').mean().favorite_count.sort_values(axis=0,ascending=False).index[:11]
# Get data frame with top ten dog breeds 
df_top_breeds = df_archive[df_archive.selected_breed.isin(top_favorite_breeds)]
# Plot the top ten dog breeds
sb.pointplot(x = df_top_breeds.favorite_count, y = df_top_breeds.selected_breed, 
           color = 'skyblue', order = top_favorite_breeds, linestyles='');
plt.xlabel('Mean favorite count');
plt.ylabel('');
plt.title('Top ten dog breeds in terms of mean "likes"');
plt.xticks(rotation=30);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10241891835630126, 'fraction_numerical': 0.033515133852366874, 'mean_word_length': 4.212673611111111, 'pattern_counts': {'":': 0, '<': 131, '<?xml version=': 0, '>': 131, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '32', 'dir': 'jupyter-structured-clean-dedup', 'id': '505998', 'license': 'MIT', 'n_tokens_mistral': 8506, 'n_tokens_neox': 7820, 'n_words': 2332, 'path': 'wrangle_act.ipynb', 'repo_name': 'zoraaroz/wrangling-project', 'size': '24019'}