In this notebook, we will do a comprehensive analysis of the Android app market by comparing thousands of apps in the Google Play store.
Data Source:
App and review data was scraped from the Google Play Store by Lavanya Gupta in 2018. Original files listed here.
import pandas as pd
import plotly.express as px
# Show numeric output in decimal format e.g., 2.15
pd.options.display.float_format = '{:,.2f}'.format
df_apps = pd.read_csv('apps.csv')
Challenge: How many rows and columns does df_apps have? What are the column names? Look at a random sample of 5 different rows with .sample().
df_apps.shape
(10841, 12)
df_apps.sample(5)
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | Last_Updated | Android_Ver | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1823 | LEADS FA | FINANCE | NaN | 31 | 14.00 | 1,000 | Free | 0 | Everyone | Finance | October 17, 2017 | 4.1 and up |
| 6934 | Living Smart Home | HOUSE_AND_HOME | 4.60 | 39189 | 8.85 | 1,000,000 | Free | 0 | Everyone | House & Home | July 30, 2018 | Varies with device |
| 530 | qEG APP / Química EG SRL | TOOLS | NaN | 0 | 0.12 | 10 | Free | 0 | Everyone | Tools | July 24, 2018 | 4.0 and up |
| 6890 | Robinhood - Investing, No Fees | FINANCE | 4.60 | 57493 | 9.15 | 1,000,000 | Free | 0 | Everyone | Finance | July 31, 2018 | Varies with device |
| 8886 | My Photo Keyboard | PHOTOGRAPHY | 4.10 | 211620 | 20.00 | 10,000,000 | Free | 0 | Everyone | Photography | March 29, 2018 | 4.0 and up |
df_apps.columns
Index(['App', 'Category', 'Rating', 'Reviews', 'Size_MBs', 'Installs', 'Type',
'Price', 'Content_Rating', 'Genres', 'Last_Updated', 'Android_Ver'],
dtype='object')
Challenge: Remove the columns called Last_Updated and Android_Version from the DataFrame. We will not use these columns.
df_apps.drop(["Last_Updated", "Android_Ver"], axis=1, inplace=True)
df_apps.head()
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Ak Parti Yardım Toplama | SOCIAL | NaN | 0 | 8.70 | 0 | Paid | $13.99 | Teen | Social |
| 1 | Ain Arabic Kids Alif Ba ta | FAMILY | NaN | 0 | 33.00 | 0 | Paid | $2.99 | Everyone | Education |
| 2 | Popsicle Launcher for Android P 9.0 launcher | PERSONALIZATION | NaN | 0 | 5.50 | 0 | Paid | $1.49 | Everyone | Personalization |
| 3 | Command & Conquer: Rivals | FAMILY | NaN | 0 | 19.00 | 0 | NaN | 0 | Everyone 10+ | Strategy |
| 4 | CX Network | BUSINESS | NaN | 0 | 10.00 | 0 | Free | 0 | Everyone | Business |
Challenge: How may rows have a NaN value (not-a-number) in the Ratings column? Create DataFrame called df_apps_clean that does not include these rows.
# df_apps.isna().values.any()
nan_rows = df_apps[df_apps.Rating.isna()]
nan_rows.head()
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Ak Parti Yardım Toplama | SOCIAL | NaN | 0 | 8.70 | 0 | Paid | $13.99 | Teen | Social |
| 1 | Ain Arabic Kids Alif Ba ta | FAMILY | NaN | 0 | 33.00 | 0 | Paid | $2.99 | Everyone | Education |
| 2 | Popsicle Launcher for Android P 9.0 launcher | PERSONALIZATION | NaN | 0 | 5.50 | 0 | Paid | $1.49 | Everyone | Personalization |
| 3 | Command & Conquer: Rivals | FAMILY | NaN | 0 | 19.00 | 0 | NaN | 0 | Everyone 10+ | Strategy |
| 4 | CX Network | BUSINESS | NaN | 0 | 10.00 | 0 | Free | 0 | Everyone | Business |
df_apps_clean = df_apps.dropna()
df_apps_clean.shape
(9367, 10)
Challenge: Are there any duplicates in data? Check for duplicates using the .duplicated() function. How many entries can you find for the "Instagram" app? Use .drop_duplicates() to remove any duplicates from df_apps_clean.
duplicated_rows = df_apps_clean[df_apps_clean.duplicated()]
duplicated_rows
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 946 | 420 BZ Budeze Delivery | MEDICAL | 5.00 | 2 | 11.00 | 100 | Free | 0 | Mature 17+ | Medical |
| 1133 | MouseMingle | DATING | 2.70 | 3 | 3.90 | 100 | Free | 0 | Mature 17+ | Dating |
| 1196 | Cardiac diagnosis (heart rate, arrhythmia) | MEDICAL | 4.40 | 8 | 6.50 | 100 | Paid | $12.99 | Everyone | Medical |
| 1231 | Sway Medical | MEDICAL | 5.00 | 3 | 22.00 | 100 | Free | 0 | Everyone | Medical |
| 1247 | Chat Kids - Chat Room For Kids | DATING | 4.70 | 6 | 4.90 | 100 | Free | 0 | Mature 17+ | Dating |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 10802 | Skype - free IM & video calls | COMMUNICATION | 4.10 | 10484169 | 3.50 | 1,000,000,000 | Free | 0 | Everyone | Communication |
| 10809 | SOCIAL | 4.50 | 66577313 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social | |
| 10826 | Google Drive | PRODUCTIVITY | 4.40 | 2731211 | 4.00 | 1,000,000,000 | Free | 0 | Everyone | Productivity |
| 10832 | Google News | NEWS_AND_MAGAZINES | 3.90 | 877635 | 13.00 | 1,000,000,000 | Free | 0 | Teen | News & Magazines |
| 10839 | Subway Surfers | GAME | 4.50 | 27725352 | 76.00 | 1,000,000,000 | Free | 0 | Everyone 10+ | Arcade |
476 rows × 10 columns
df_apps_clean[df_apps_clean.App == "Instagram"]
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 10806 | SOCIAL | 4.50 | 66577313 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social | |
| 10808 | SOCIAL | 4.50 | 66577446 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social | |
| 10809 | SOCIAL | 4.50 | 66577313 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social | |
| 10810 | SOCIAL | 4.50 | 66509917 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social |
df_apps_clean = df_apps_clean.drop_duplicates()
df_apps_clean[df_apps_clean.App == "Instagram"]
# Different Ratings hence Instagram not dropped - .drop_duplicates() is too strict
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 10806 | SOCIAL | 4.50 | 66577313 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social | |
| 10808 | SOCIAL | 4.50 | 66577446 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social | |
| 10810 | SOCIAL | 4.50 | 66509917 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social |
# Need to identify subset for identifying duplicates
df_apps_clean = df_apps_clean.drop_duplicates(subset=["App", "Type", "Price"])
df_apps_clean[df_apps_clean.App == "Instagram"]
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 10806 | SOCIAL | 4.50 | 66577313 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social |
df_apps_clean.shape
(8199, 10)
Challenge: Identify which apps are the highest rated. What problem might you encounter if you rely exclusively on ratings alone to determine the quality of an app?
df_apps_clean.sort_values("Rating", ascending=False).head(10)
# Number of Reviews per app is very low
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 21 | KBA-EZ Health Guide | MEDICAL | 5.00 | 4 | 25.00 | 1 | Free | 0 | Everyone | Medical |
| 1230 | Sway Medical | MEDICAL | 5.00 | 3 | 22.00 | 100 | Free | 0 | Everyone | Medical |
| 1227 | AJ Men's Grooming | LIFESTYLE | 5.00 | 2 | 22.00 | 100 | Free | 0 | Everyone | Lifestyle |
| 1224 | FK Dedinje BGD | SPORTS | 5.00 | 36 | 2.60 | 100 | Free | 0 | Everyone | Sports |
| 1223 | CB VIDEO VISION | PHOTOGRAPHY | 5.00 | 13 | 2.60 | 100 | Free | 0 | Everyone | Photography |
| 1222 | Beacon Baptist Jupiter, FL | LIFESTYLE | 5.00 | 14 | 2.60 | 100 | Free | 0 | Everyone | Lifestyle |
| 1214 | BV Mobile Apps | PRODUCTIVITY | 5.00 | 3 | 4.80 | 100 | Free | 0 | Everyone | Productivity |
| 2680 | Florida Wildflowers | FAMILY | 5.00 | 5 | 69.00 | 1,000 | Free | 0 | Everyone | Education |
| 1206 | ADS-B Driver | TOOLS | 5.00 | 2 | 6.30 | 100 | Paid | $1.99 | Everyone | Tools |
| 2750 | Superheroes, Marvel, DC, Comics, TV, Movies News | COMICS | 5.00 | 34 | 12.00 | 5,000 | Free | 0 | Everyone | Comics |
Challenge: What's the size in megabytes (MB) of the largest Android apps in the Google Play Store. Based on the data, do you think there could be limit in place or can developers make apps as large as they please?
df_apps_clean.sort_values("Size_MBs", ascending=False).head(10)
# Max size 100 Mb
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 9942 | Talking Babsy Baby: Baby Games | LIFESTYLE | 4.00 | 140995 | 100.00 | 10,000,000 | Free | 0 | Everyone | Lifestyle;Pretend Play |
| 10687 | Hungry Shark Evolution | GAME | 4.50 | 6074334 | 100.00 | 100,000,000 | Free | 0 | Teen | Arcade |
| 9943 | Miami crime simulator | GAME | 4.00 | 254518 | 100.00 | 10,000,000 | Free | 0 | Mature 17+ | Action |
| 9944 | Gangster Town: Vice District | FAMILY | 4.30 | 65146 | 100.00 | 10,000,000 | Free | 0 | Mature 17+ | Simulation |
| 3144 | Vi Trainer | HEALTH_AND_FITNESS | 3.60 | 124 | 100.00 | 5,000 | Free | 0 | Everyone | Health & Fitness |
| 9945 | Ultimate Tennis | SPORTS | 4.30 | 183004 | 100.00 | 10,000,000 | Free | 0 | Everyone | Sports |
| 7926 | Post Bank | FINANCE | 4.50 | 60449 | 100.00 | 1,000,000 | Free | 0 | Everyone | Finance |
| 7927 | The Walking Dead: Our World | GAME | 4.00 | 22435 | 100.00 | 1,000,000 | Free | 0 | Teen | Action |
| 7928 | Stickman Legends: Shadow Wars | GAME | 4.40 | 38419 | 100.00 | 1,000,000 | Paid | $0.99 | Everyone 10+ | Action |
| 4176 | Car Crash III Beam DH Real Damage Simulator 2018 | GAME | 3.60 | 151 | 100.00 | 10,000 | Free | 0 | Everyone | Racing |
Challenge: Which apps have the highest number of reviews? Are there any paid apps among the top 50?
df_apps_clean.sort_values("Reviews", ascending=False).head(50)
# Most Reviewed Apps are Free
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 10805 | SOCIAL | 4.10 | 78158306 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social | |
| 10785 | WhatsApp Messenger | COMMUNICATION | 4.40 | 69119316 | 3.50 | 1,000,000,000 | Free | 0 | Everyone | Communication |
| 10806 | SOCIAL | 4.50 | 66577313 | 5.30 | 1,000,000,000 | Free | 0 | Teen | Social | |
| 10784 | Messenger – Text and Video Chat for Free | COMMUNICATION | 4.00 | 56642847 | 3.50 | 1,000,000,000 | Free | 0 | Everyone | Communication |
| 10650 | Clash of Clans | GAME | 4.60 | 44891723 | 98.00 | 100,000,000 | Free | 0 | Everyone 10+ | Strategy |
| 10744 | Clean Master- Space Cleaner & Antivirus | TOOLS | 4.70 | 42916526 | 3.40 | 500,000,000 | Free | 0 | Everyone | Tools |
| 10835 | Subway Surfers | GAME | 4.50 | 27722264 | 76.00 | 1,000,000,000 | Free | 0 | Everyone 10+ | Arcade |
| 10828 | YouTube | VIDEO_PLAYERS | 4.30 | 25655305 | 4.65 | 1,000,000,000 | Free | 0 | Teen | Video Players & Editors |
| 10746 | Security Master - Antivirus, VPN, AppLock, Boo... | TOOLS | 4.70 | 24900999 | 3.40 | 500,000,000 | Free | 0 | Everyone | Tools |
| 10584 | Clash Royale | GAME | 4.60 | 23133508 | 97.00 | 100,000,000 | Free | 0 | Everyone 10+ | Strategy |
| 10763 | Candy Crush Saga | GAME | 4.40 | 22426677 | 74.00 | 500,000,000 | Free | 0 | Everyone | Casual |
| 10770 | UC Browser - Fast Download Private & Secure | COMMUNICATION | 4.50 | 17712922 | 40.00 | 500,000,000 | Free | 0 | Teen | Communication |
| 10735 | Snapchat | SOCIAL | 4.00 | 17014787 | 5.30 | 500,000,000 | Free | 0 | Teen | Social |
| 10489 | 360 Security - Free Antivirus, Booster, Cleaner | TOOLS | 4.60 | 16771865 | 3.40 | 100,000,000 | Free | 0 | Everyone | Tools |
| 10731 | My Talking Tom | GAME | 4.50 | 14891223 | 36.00 | 500,000,000 | Free | 0 | Everyone | Casual |
| 10594 | 8 Ball Pool | GAME | 4.50 | 14198297 | 52.00 | 100,000,000 | Free | 0 | Everyone | Sports |
| 10302 | DU Battery Saver - Battery Charger & Battery Life | TOOLS | 4.50 | 13479633 | 14.00 | 100,000,000 | Free | 0 | Everyone | Tools |
| 10354 | BBM - Free Calls & Messages | COMMUNICATION | 4.30 | 12842860 | 3.50 | 100,000,000 | Free | 0 | Everyone | Communication |
| 10549 | Cache Cleaner-DU Speed Booster (booster & clea... | TOOLS | 4.50 | 12759663 | 15.00 | 100,000,000 | Free | 0 | Everyone | Tools |
| 10757 | NEWS_AND_MAGAZINES | 4.30 | 11667403 | 6.30 | 500,000,000 | Free | 0 | Mature 17+ | News & Magazines | |
| 10721 | Viber Messenger | COMMUNICATION | 4.30 | 11334799 | 3.50 | 500,000,000 | Free | 0 | Everyone | Communication |
| 10578 | Shadow Fight 2 | GAME | 4.60 | 10979062 | 88.00 | 100,000,000 | Free | 0 | Everyone 10+ | Action |
| 10813 | Google Photos | PHOTOGRAPHY | 4.50 | 10858556 | 6.90 | 1,000,000,000 | Free | 0 | Everyone | Photography |
| 10724 | LINE: Free Calls & Messages | COMMUNICATION | 4.20 | 10790289 | 3.50 | 500,000,000 | Free | 0 | Everyone | Communication |
| 10717 | Pou | GAME | 4.30 | 10485308 | 24.00 | 500,000,000 | Free | 0 | Everyone | Casual |
| 10792 | Skype - free IM & video calls | COMMUNICATION | 4.10 | 10484169 | 3.50 | 1,000,000,000 | Free | 0 | Everyone | Communication |
| 10628 | Pokémon GO | GAME | 4.10 | 10424925 | 85.00 | 100,000,000 | Free | 0 | Everyone | Adventure |
| 10388 | Minion Rush: Despicable Me Official Game | GAME | 4.50 | 10216538 | 36.00 | 100,000,000 | Free | 0 | Everyone 10+ | Casual;Action & Adventure |
| 10694 | Yes day | GAME | 4.50 | 10055521 | 94.00 | 100,000,000 | Free | 0 | Everyone | Casual |
| 10695 | Hay Day | FAMILY | 4.50 | 10053186 | 94.00 | 100,000,000 | Free | 0 | Everyone | Casual |
| 10644 | Dream League Soccer 2018 | GAME | 4.60 | 9882639 | 74.00 | 100,000,000 | Free | 0 | Everyone | Sports |
| 10696 | My Talking Angela | GAME | 4.50 | 9881829 | 99.00 | 100,000,000 | Free | 0 | Everyone | Casual |
| 10660 | VivaVideo - Video Editor & Photo Movie | VIDEO_PLAYERS | 4.60 | 9879473 | 40.00 | 100,000,000 | Free | 0 | Teen | Video Players & Editors |
| 10786 | Google Chrome: Fast & Secure | COMMUNICATION | 4.30 | 9642995 | 3.50 | 1,000,000,000 | Free | 0 | Everyone | Communication |
| 10817 | Maps - Navigate & Explore | TRAVEL_AND_LOCAL | 4.30 | 9235155 | 12.00 | 1,000,000,000 | Free | 0 | Everyone | Travel & Local |
| 10672 | Hill Climb Racing | GAME | 4.40 | 8923587 | 63.00 | 100,000,000 | Free | 0 | Everyone | Racing |
| 10734 | Facebook Lite | SOCIAL | 4.30 | 8606259 | 5.30 | 500,000,000 | Free | 0 | Teen | Social |
| 10649 | Asphalt 8: Airborne | GAME | 4.50 | 8389714 | 92.00 | 100,000,000 | Free | 0 | Teen | Racing |
| 10699 | Mobile Legends: Bang Bang | GAME | 4.40 | 8219586 | 99.00 | 100,000,000 | Free | 0 | Teen | Action |
| 10322 | Battery Doctor-Battery Life Saver & Battery Co... | TOOLS | 4.50 | 8190074 | 17.00 | 100,000,000 | Free | 0 | Everyone | Tools |
| 10396 | Piano Tiles 2™ | GAME | 4.70 | 8118880 | 36.00 | 100,000,000 | Free | 0 | Everyone | Arcade |
| 10777 | Temple Run 2 | GAME | 4.30 | 8118609 | 62.00 | 500,000,000 | Free | 0 | Everyone | Action |
| 10822 | TOOLS | 4.40 | 8033493 | 3.40 | 1,000,000,000 | Free | 0 | Everyone | Tools | |
| 10359 | Truecaller: Caller ID, SMS spam blocking & Dialer | COMMUNICATION | 4.50 | 7820209 | 3.50 | 100,000,000 | Free | 0 | Everyone | Communication |
| 10711 | SHAREit - Transfer & Share | TOOLS | 4.60 | 7790693 | 17.00 | 500,000,000 | Free | 0 | Everyone | Tools |
| 10389 | Sniper 3D Gun Shooter: Free Shooting Games - FPS | GAME | 4.60 | 7671249 | 36.00 | 100,000,000 | Free | 0 | Mature 17+ | Action |
| 10676 | Farm Heroes Saga | GAME | 4.40 | 7614130 | 70.00 | 100,000,000 | Free | 0 | Everyone | Casual |
| 10576 | PicsArt Photo Studio: Collage Maker & Pic Editor | PHOTOGRAPHY | 4.50 | 7594559 | 34.00 | 100,000,000 | Free | 0 | Teen | Photography |
| 10461 | PhotoGrid: Video & Pic Collage Maker, Photo Ed... | PHOTOGRAPHY | 4.60 | 7529865 | 6.90 | 100,000,000 | Free | 0 | Everyone | Photography |
| 10502 | GO Launcher - 3D parallax Themes & HD Wallpapers | PERSONALIZATION | 4.50 | 7464996 | 6.15 | 100,000,000 | Free | 0 | Everyone | Personalization |
content_ratings = df_apps_clean.Content_Rating.value_counts()
content_ratings
Everyone 6621 Teen 912 Mature 17+ 357 Everyone 10+ 305 Adults only 18+ 3 Unrated 1 Name: Content_Rating, dtype: int64
fig = px.pie(labels=content_ratings.index, values=content_ratings.values)
fig.show()
fig = px.pie(labels=content_ratings.index, values=content_ratings.values, title="Content Ratings", names=content_ratings.index)
fig.update_traces(textposition="outside", textinfo="percent+label")
fig.show()
fig = px.pie(labels=content_ratings.index, values=content_ratings.values, title="Content Ratings", names=content_ratings.index, hole=0.7)
fig.update_traces(textposition="inside", textinfo="percent", textfont_size=15)
fig.show()
Challenge: How many apps had over 1 billion (that's right - BILLION) installations? How many apps just had a single install?
Check the datatype of the Installs column.
Count the number of apps at each level of installations.
Convert the number of installations (the Installs column) to a numeric data type. Hint: this is a 2-step process. You'll have make sure you remove non-numeric characters first.
df_apps_clean.Installs.describe()
count 8199 unique 19 top 1,000,000 freq 1417 Name: Installs, dtype: object
df_apps_clean.info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 8199 entries, 21 to 10835 Data columns (total 10 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 App 8199 non-null object 1 Category 8199 non-null object 2 Rating 8199 non-null float64 3 Reviews 8199 non-null int64 4 Size_MBs 8199 non-null float64 5 Installs 8199 non-null object 6 Type 8199 non-null object 7 Price 8199 non-null object 8 Content_Rating 8199 non-null object 9 Genres 8199 non-null object dtypes: float64(2), int64(1), object(7) memory usage: 704.6+ KB
df_apps_clean[['App', 'Installs']].groupby("Installs").count()
| App | |
|---|---|
| Installs | |
| 1 | 3 |
| 1,000 | 698 |
| 1,000,000 | 1417 |
| 1,000,000,000 | 20 |
| 10 | 69 |
| 10,000 | 988 |
| 10,000,000 | 933 |
| 100 | 303 |
| 100,000 | 1096 |
| 100,000,000 | 189 |
| 5 | 9 |
| 5,000 | 425 |
| 5,000,000 | 607 |
| 50 | 56 |
| 50,000 | 457 |
| 50,000,000 | 202 |
| 500 | 199 |
| 500,000 | 504 |
| 500,000,000 | 24 |
df_apps_clean.Installs = df_apps_clean.Installs.astype(str).str.replace(',', '')
df_apps_clean.Installs = pd.to_numeric(df_apps_clean.Installs)
df_apps_clean[['App', 'Installs']].groupby("Installs").count()
| App | |
|---|---|
| Installs | |
| 1 | 3 |
| 5 | 9 |
| 10 | 69 |
| 50 | 56 |
| 100 | 303 |
| 500 | 199 |
| 1000 | 698 |
| 5000 | 425 |
| 10000 | 988 |
| 50000 | 457 |
| 100000 | 1096 |
| 500000 | 504 |
| 1000000 | 1417 |
| 5000000 | 607 |
| 10000000 | 933 |
| 50000000 | 202 |
| 100000000 | 189 |
| 500000000 | 24 |
| 1000000000 | 20 |
Let's examine the Price column more closely.
Challenge: Convert the price column to numeric data. Then investigate the top 20 most expensive apps in the dataset.
Remove all apps that cost more than $250 from the df_apps_clean DataFrame.
Add a column called 'Revenue_Estimate' to the DataFrame. This column should hold the price of the app times the number of installs. What are the top 10 highest grossing paid apps according to this estimate? Out of the top 10 highest grossing paid apps, how many are games?
df_apps_clean.Price = df_apps_clean.Price.astype(str).str.replace('$', '')
df_apps_clean.Price = pd.to_numeric(df_apps_clean.Price)
df_apps_clean.Price.describe()
/var/folders/mj/365hbdq166n0n8b1hxp26g9h0000gn/T/ipykernel_99431/1957155207.py:1: FutureWarning: The default value of regex will change from True to False in a future version. In addition, single character regular expressions will *not* be treated as literal strings when regex=True.
count 8,199.00 mean 1.04 std 16.85 min 0.00 25% 0.00 50% 0.00 75% 0.00 max 400.00 Name: Price, dtype: float64
df_apps_clean.sort_values('Price', ascending=False).head(20)
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 3946 | I'm Rich - Trump Edition | LIFESTYLE | 3.60 | 275 | 7.30 | 10000 | Paid | 400.00 | Everyone | Lifestyle |
| 2461 | I AM RICH PRO PLUS | FINANCE | 4.00 | 36 | 41.00 | 1000 | Paid | 399.99 | Everyone | Finance |
| 4606 | I Am Rich Premium | FINANCE | 4.10 | 1867 | 4.70 | 50000 | Paid | 399.99 | Everyone | Finance |
| 3145 | I am rich(premium) | FINANCE | 3.50 | 472 | 0.94 | 5000 | Paid | 399.99 | Everyone | Finance |
| 3554 | 💎 I'm rich | LIFESTYLE | 3.80 | 718 | 26.00 | 10000 | Paid | 399.99 | Everyone | Lifestyle |
| 5765 | I am rich | LIFESTYLE | 3.80 | 3547 | 1.80 | 100000 | Paid | 399.99 | Everyone | Lifestyle |
| 1946 | I am rich (Most expensive app) | FINANCE | 4.10 | 129 | 2.70 | 1000 | Paid | 399.99 | Teen | Finance |
| 2775 | I Am Rich Pro | FAMILY | 4.40 | 201 | 2.70 | 5000 | Paid | 399.99 | Everyone | Entertainment |
| 3221 | I am Rich Plus | FAMILY | 4.00 | 856 | 8.70 | 10000 | Paid | 399.99 | Everyone | Entertainment |
| 3114 | I am Rich | FINANCE | 4.30 | 180 | 3.80 | 5000 | Paid | 399.99 | Everyone | Finance |
| 1331 | most expensive app (H) | FAMILY | 4.30 | 6 | 1.50 | 100 | Paid | 399.99 | Everyone | Entertainment |
| 2394 | I am Rich! | FINANCE | 3.80 | 93 | 22.00 | 1000 | Paid | 399.99 | Everyone | Finance |
| 3897 | I Am Rich | FAMILY | 3.60 | 217 | 4.90 | 10000 | Paid | 389.99 | Everyone | Entertainment |
| 2193 | I am extremely Rich | LIFESTYLE | 2.90 | 41 | 2.90 | 1000 | Paid | 379.99 | Everyone | Lifestyle |
| 3856 | I am rich VIP | LIFESTYLE | 3.80 | 411 | 2.60 | 10000 | Paid | 299.99 | Everyone | Lifestyle |
| 2281 | Vargo Anesthesia Mega App | MEDICAL | 4.60 | 92 | 32.00 | 1000 | Paid | 79.99 | Everyone | Medical |
| 1407 | LTC AS Legal | MEDICAL | 4.00 | 6 | 1.30 | 100 | Paid | 39.99 | Everyone | Medical |
| 2629 | I am Rich Person | LIFESTYLE | 4.20 | 134 | 1.80 | 1000 | Paid | 37.99 | Everyone | Lifestyle |
| 2481 | A Manual of Acupuncture | MEDICAL | 3.50 | 214 | 68.00 | 1000 | Paid | 33.99 | Everyone | Medical |
| 4264 | Golfshot Plus: Golf GPS | SPORTS | 4.10 | 3387 | 25.00 | 50000 | Paid | 29.99 | Everyone | Sports |
df_apps_clean = df_apps_clean[df_apps_clean["Price"] < 250]
df_apps_clean.sort_values("Price", ascending=False).head()
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | |
|---|---|---|---|---|---|---|---|---|---|---|
| 2281 | Vargo Anesthesia Mega App | MEDICAL | 4.60 | 92 | 32.00 | 1000 | Paid | 79.99 | Everyone | Medical |
| 1407 | LTC AS Legal | MEDICAL | 4.00 | 6 | 1.30 | 100 | Paid | 39.99 | Everyone | Medical |
| 2629 | I am Rich Person | LIFESTYLE | 4.20 | 134 | 1.80 | 1000 | Paid | 37.99 | Everyone | Lifestyle |
| 2481 | A Manual of Acupuncture | MEDICAL | 3.50 | 214 | 68.00 | 1000 | Paid | 33.99 | Everyone | Medical |
| 2463 | PTA Content Master | MEDICAL | 4.20 | 64 | 41.00 | 1000 | Paid | 29.99 | Everyone | Medical |
df_apps_clean["Revenue Estimates"] = df_apps_clean["Installs"].multiply(df_apps_clean.Price)
df_apps_clean.sort_values("Revenue Estimates", ascending=False).head()
| App | Category | Rating | Reviews | Size_MBs | Installs | Type | Price | Content_Rating | Genres | Revenue Estimates | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 9220 | Minecraft | FAMILY | 4.50 | 2376564 | 19.00 | 10000000 | Paid | 6.99 | Everyone 10+ | Arcade;Action & Adventure | 69,900,000.00 |
| 8825 | Hitman Sniper | GAME | 4.60 | 408292 | 29.00 | 10000000 | Paid | 0.99 | Mature 17+ | Action | 9,900,000.00 |
| 7151 | Grand Theft Auto: San Andreas | GAME | 4.40 | 348962 | 26.00 | 1000000 | Paid | 6.99 | Mature 17+ | Action | 6,990,000.00 |
| 7477 | Facetune - For Free | PHOTOGRAPHY | 4.40 | 49553 | 48.00 | 1000000 | Paid | 5.99 | Everyone | Photography | 5,990,000.00 |
| 7977 | Sleep as Android Unlock | LIFESTYLE | 4.50 | 23966 | 0.85 | 1000000 | Paid | 5.99 | Everyone | Lifestyle | 5,990,000.00 |
df_apps_clean.Category.nunique()
33
top10_category = df_apps_clean.Category.value_counts()[:10]
top10_category
FAMILY 1606 GAME 910 TOOLS 719 PRODUCTIVITY 301 PERSONALIZATION 298 LIFESTYLE 297 FINANCE 296 MEDICAL 292 PHOTOGRAPHY 263 BUSINESS 262 Name: Category, dtype: int64
bar = px.bar(x=top10_category.index, y=top10_category.values)
bar.show()
category_installs = df_apps_clean.groupby("Category").agg({"Installs": pd.Series.sum})
category_installs.sort_values("Installs", ascending=True, inplace=True)
category_installs.head()
| Installs | |
|---|---|
| Category | |
| EVENTS | 15949410 |
| BEAUTY | 26916200 |
| PARENTING | 31116110 |
| MEDICAL | 39162676 |
| COMICS | 44931100 |
h_bar = px.bar(y=category_installs.index, x=category_installs.Installs, orientation='h')
h_bar.update_layout(xaxis_title='Number of Downloads', yaxis_title='Category')
h_bar.show()
Challenge:
First, create a DataFrame that has the number of apps in one column and the number of installs in another
Then use the plotly express examples from the documentation alongside the .scatter() API referenceto create scatter plot.
Hint: Use the size, hover_name and color parameters in .scatter(). To scale the yaxis, call .update_layout() and specify that the yaxis should be on a log-scale like so: yaxis=dict(type='log')
cat_apps = df_apps_clean.groupby("Category").agg({"App": pd.Series.count})
cat_merged_df = pd.merge(cat_apps, category_installs, on="Category")
cat_merged_df.head()
| App | Installs | |
|---|---|---|
| Category | ||
| ART_AND_DESIGN | 61 | 114233100 |
| AUTO_AND_VEHICLES | 73 | 53129800 |
| BEAUTY | 42 | 26916200 |
| BOOKS_AND_REFERENCE | 169 | 1665791655 |
| BUSINESS | 262 | 692018120 |
scatter = px.scatter(cat_merged_df, # data
x="App", # Column Name
y="Installs",
title="Category Concentration",
size="App", # Size of Dots
hover_name=cat_merged_df.index,
color="Installs")
scatter.update_layout(xaxis_title="Number of Apps (Lower = More Concentration)",
yaxis_title="Installs",
yaxis=dict(type='log'))
scatter.show()
Challenge: How many different types of genres are there? Can an app belong to more than one genre? Check what happens when you use .value_counts() on a column with nested values? See if you can work around this problem by using the .split() function and the DataFrame's .stack() method.
# Number of Genres
len(df_apps_clean.Genres.unique())
# df_apps_clean.Genres.nunique()
114
# Problem: Have multiple Genres separated by ;
df_apps_clean.Genres.value_counts().sort_values()[:5]
Lifestyle;Pretend Play 1 Strategy;Education 1 Adventure;Education 1 Role Playing;Brain Games 1 Tools;Education 1 Name: Genres, dtype: int64
# Split the string on ; and then .stack() them
stack = df_apps_clean.Genres.str.split(';', expand=True).stack()
num_genres = stack.value_counts()
len(num_genres)
53
Challenge: Can you create this chart with the Series containing the genre data?
Try experimenting with the built in colour scales in Plotly. You can find a full list here.
bar = px.bar(x=num_genres.index[:15], # Index: Name of Category
y=num_genres.values[:15], # Values: number of times the genre was repeated
title="Top Genres",
hover_name=num_genres.index[:15],
color=num_genres.values[:15],
color_continuous_scale="Agsunset",)
bar.update_layout(xaxis_title='Genre',
yaxis_title='Number of Apps',
coloraxis_showscale=False)
bar.show()
df_apps_clean.Type.value_counts()
Free 7595 Paid 589 Name: Type, dtype: int64
df_free_vs_paid = df_apps_clean.groupby(["Category", "Type"], as_index=False).agg({"App":pd.Series.count})
df_free_vs_paid.head()
| Category | Type | App | |
|---|---|---|---|
| 0 | ART_AND_DESIGN | Free | 58 |
| 1 | ART_AND_DESIGN | Paid | 3 |
| 2 | AUTO_AND_VEHICLES | Free | 72 |
| 3 | AUTO_AND_VEHICLES | Paid | 1 |
| 4 | BEAUTY | Free | 42 |
Challenge: Use the plotly express bar chart examples and the .bar() API reference to create this bar chart.
You'll want to use the df_free_vs_paid DataFrame that you created above that has the total number of free and paid apps per category.
See if you can figure out how to get the look above by changing the categoryorder to 'total descending' as outlined in the documentation here here.
g_bar = px.bar(df_free_vs_paid,
x="Category",
y="App",
title="Free v/s Paid Apps by Category",
color="Type",
barmode="group")
g_bar.update_layout(xaxis_title="Category",
yaxis_title="Number of Apps",
yaxis=dict(type='log'),
xaxis={'categoryorder': 'total descending'})
g_bar.show()
Challenge: Create a box plot that shows the number of Installs for free versus paid apps. How does the median number of installations compare? Is the difference large or small?
Use the Box Plots Guide and the .box API reference to create the chart.
box = px.box(df_apps_clean,
y='Installs',
x='Type',
color='Type',
points='all',
notched=True,
title='How Many Downloads are Paid Apps Giving Up?')
box.update_layout(yaxis=dict(type='log'))
box.show()
Challenge:
Looking at the hover text, how much does the median app earn in the Tools category? If developing an Android app costs $30,000 or thereabouts, does the average photography app recoup its development costs?
Hint: I've used 'min ascending' to sort the categories.
df_paid_apps = df_apps_clean[df_apps_clean['Type'] == 'Paid']
box = px.box(df_paid_apps,
x='Category',
y='Revenue Estimates',
title='How Much Can Paid Apps Earn?')
box.update_layout(xaxis_title='Category',
yaxis_title='Paid App Ballpark Revenue',
xaxis={'categoryorder':'min ascending'},
yaxis=dict(type='log'))
box.show()