Generative AI has become an indispensable part of our daily lives. According to statistics released by Adobe in April 2024, 53% of Americans have used generative models, with 81% applying them for personal tasks, 30% for work, and 17% for academic purposes. As the market has grown, the variety of generative AI services has diversified, and competition has intensified. As of January 2025, there are approximately 67,000 companies related to generative AI. In this vast generative AI market, it is crucial to first understand how different generative AI apps are perceived by users in terms of their key characteristics and satisfaction to deliver attractive services to consumers. Accordingly, the primary research question set for this study was: “How are five generative apps positioned among users in terms of satisfaction and use?” To address this, the following sub-questions were developed:
To answer these questions, sentiment analysis, tf-idf analysis, and bigram analysis were conducted. The results, based on reviews written in early 2024, allowed for the classification of the five AI apps by satisfaction and use. Satisfaction was defined by how positive users’ emotions were toward each app. Use was determined by whether users recognized the app’s primary purpose as new content generation, or whether they perceived it as serving other purposes such as information retrieval or as an assistant. Using the ‘afinn’ lexicon, average sentiment scores were calculated, ranking the apps as follows: Copilot, ChatGPT, BingAI, DaVinci, and Gemini. The apps were mapped according to the actual gaps in sentiment scores. For ChatGPT, tf-idf and bigram analyses confirmed active use for information retrieval, image generation, and essay writing. Copilot showed similar patterns to ChatGPT but with relatively more mentions of image generation. Bing was mainly used for search purposes, with significantly more mentions related to app-tech and auxiliary uses. DaVinci was found to be specialized in image and design generation based on frequently mentioned words. Lastly, Gemini was primarily used as a replacement for Google Assistant to assist with phone functions, with dissatisfaction noted regarding its generative features such as note creation. This analysis was conducted using reviews collected in early 2024, so its timeliness may be somewhat limited. The uneven distribution of review counts, platforms, and collection periods also makes generalization difficult. Additionally, it was challenging to compare app-specific differentiators with other AI services provided on computers using reviews alone. Therefore, collecting more recent reviews—including those from communities like Reddit—and conducting positioning analyses across more than two dimensions would be a meaningful direction for future research.
The review data for generative AI apps was downloaded from Kaggle, extracted by Reham Alabduljabbar. The dataset consists of reviews from users of five generative AI applications: ChatGPT, Bing AI, Microsoft Co-Pilot, Gemini AI, and Da Vinci AI. User reviews were collected from the App Store and Google Play between January 2023 and March 2024, all written in English by users in the United States. The distribution of review periods and platforms varies by app, as shown in the accompanying table. Notably, no reviews for Gemini were collected from the App Store, and only one review for DaVinci was collected from Google Play. Additionally, Gemini reviews were collected only in March 2024, and Copilot reviews were collected starting from December 2023, unlike the other apps. Investigation of app release dates confirmed that Gemini was not available on the App Store until November 2024, making review collection before March 2024 impossible. On Google Play, Gemini was released in early February 2024, and review activity increased from March onward.
The dataset used for analysis consists of a total of 7,736 reviews (rows) and 12 columns: ‘No.of.reviews’, ‘review_id’ (reviewer ID), ‘source’ (review platform), ‘review_title’, ‘review_description’, ‘rating’ and ‘thumbs_up’ (satisfaction ratings from the app installation platform), ‘review_date’, ‘appVersion’, ‘language_code’, ‘country_code’, and ‘App_name’ (type of generative AI app)
ai_review <- read.csv("ai_app_review.csv", encoding = "UTF-8")
head(ai_review)
## No.of.reviews review_id source review_title
## 1 0 d2676cae-da30-4e57-9a05-21ee5cd78495 Google Play
## 2 1 b313673d-5446-4479-acc0-5c780181d482 Google Play
## 3 2 9bce6943-4a9e-4fc1-a2f7-eef460fd1b1d Google Play
## 4 3 eb57122a-2da6-4d25-8610-f211bf06fbe1 Google Play
## 5 4 c70e4556-b060-4538-bde3-6b272a18153c Google Play
## 6 5 0b91d0fb-d2e3-46fc-9916-8ec75e51e6fd Google Play
## review_description
## 1 quite refreshing and impressive but not sure why the search function stuck halfway, failed to load any hit even after retrying, not sure if it's the issue with my phone or internet connection but when this happen and i try Chrome it works well and fast. keep up the good job... But why it keeps force closing when I'm streaming video as well as tab freeze.
## 2 nice 🙂
## 3 ✌🏻
## 4 very good and intresting .i lov rashiya
## 5 In Bing news, there is no way to translate it, in Google news, there is option to translate it just like I do on browser. Please add basic features it's a shame
## 6 it's help me with all my mathematics assignment so for it's a solid five star 🌟
## rating thumbs_up review_date appVersion laguage_code country_code
## 1 3 0 3/24/2024 18:05 28.0.420319014 en us
## 2 1 0 3/24/2024 18:04 28.0.420319010 en us
## 3 5 0 3/24/2024 17:42 27.9.420301046 en us
## 4 5 0 3/24/2024 17:17 27.9.420301046 en us
## 5 2 0 3/24/2024 16:58 en us
## 6 5 0 3/24/2024 16:52 27.9.420301046 en us
## App_name
## 1 BingAI
## 2 BingAI
## 3 BingAI
## 4 BingAI
## 5 BingAI
## 6 BingAI
review_clean <- ai_review %>%
mutate(date = mdy_hm(review_date)) %>%
mutate(date = as.Date(date)) %>%
mutate(rating = as.numeric(rating)) %>%
rename(number = No.of.reviews, platform = source, app = App_name) %>%
select(number, platform, review_description, rating, date, app) %>%
filter(app %in% c("BingAI", "DAVINCI", "chatgpt", "copilot", "gemini")) %>%
filter(str_length(review_description) >= 5)
head(review_clean)
## number platform
## 1 0 Google Play
## 2 1 Google Play
## 3 3 Google Play
## 4 4 Google Play
## 5 5 Google Play
## 6 6 Google Play
## review_description
## 1 quite refreshing and impressive but not sure why the search function stuck halfway, failed to load any hit even after retrying, not sure if it's the issue with my phone or internet connection but when this happen and i try Chrome it works well and fast. keep up the good job... But why it keeps force closing when I'm streaming video as well as tab freeze.
## 2 nice 🙂
## 3 very good and intresting .i lov rashiya
## 4 In Bing news, there is no way to translate it, in Google news, there is option to translate it just like I do on browser. Please add basic features it's a shame
## 5 it's help me with all my mathematics assignment so for it's a solid five star 🌟
## 6 sahi h
## rating date app
## 1 3 2024-03-24 BingAI
## 2 1 2024-03-24 BingAI
## 3 5 2024-03-24 BingAI
## 4 2 2024-03-24 BingAI
## 5 5 2024-03-24 BingAI
## 6 3 2024-03-24 BingAI
tidy_review <- review_clean %>%
unnest_tokens(input = review_description, output = word, drop = F) %>%
anti_join(stop_words) %>%
select(number, app, word, rating, date, platform)
## Joining with `by = join_by(word)`
head(tidy_review)
## number app word rating date platform
## 1 0 BingAI refreshing 3 2024-03-24 Google Play
## 2 0 BingAI impressive 3 2024-03-24 Google Play
## 3 0 BingAI search 3 2024-03-24 Google Play
## 4 0 BingAI function 3 2024-03-24 Google Play
## 5 0 BingAI stuck 3 2024-03-24 Google Play
## 6 0 BingAI halfway 3 2024-03-24 Google Play
To address the first research question, sentiment analysis was performed using the ‘afinn’ lexicon, which measures both the direction (positive/negative) and intensity of emotions, enabling more precise and intuitive sentiment evaluation.
By comparing sentiment scores, I aimed to quantitatively assess the emotions users experienced while using each app. Additionally, by comparing the sentiment scores from app reviews with the rating scores provided on each platform, I sought to determine whether the sentiment expressed in written feedback was consistent with the users’ formal satisfaction ratings. For objectivity, the sentiment score was defined as the mean of the AFINN sentiment values, and the rating score as the mean of the rating values.
For visualization, a scatter plot was chosen, with the x-axis representing sentiment score and the y-axis representing rating score, so that the distribution between the two values could be easily observed. To enhance readability, the axis labels were revised, the ‘theme_minimal’ function was used to simplify the background, and the size of the points and app names was adjusted.
The results showed that all sentiment scores were above zero but generally clustered around one, indicating that overall sentiment was not particularly high. Sentiment scores were highest for Copilot, followed by ChatGPT, BingAI, DaVinci, and Gemini. Rating scores were highest for ChatGPT, then Copilot, BingAI, DaVinci, and Gemini. Except for Copilot and ChatGPT, there was a general trend that higher sentiment scores corresponded to higher rating scores, suggesting that users who used more positive words in their reviews also tended to give higher satisfaction ratings. To further refine the analysis, I examined whether there were differences between platforms. On the App Store, ChatGPT had the highest sentiment and rating scores, and DaVinci’s sentiment score was higher than BingAI’s, which differed from the combined results. On Google Play, the ranking was different: DaVinci, ChatGPT, Copilot, BingAI, and Gemini, in that order. I also examined how sentiment scores changed over time. For ChatGPT and BingAI, sentiment scores decreased and then increased again in March; for DaVinci, scores remained low until a sharp increase in March; and for Copilot, sentiment steadily increased after January. Across all apps, rating scores fluctuated greatly over time, which may reflect significant functional updates around February. While I could not find public update records for BingAI, there were documented updates for ChatGPT, Copilot, and DaVinci in February 2024. However, because the distribution of reviews by platform and time was not uniform for all apps, these results should be interpreted with caution. In particular, since there were no App Store reviews for Gemini, it was not possible to determine whether platform differences affected its evaluation.
afinn <- get_sentiments("afinn")
afinn
## # A tibble: 2,477 × 2
## word value
## <chr> <dbl>
## 1 abandon -2
## 2 abandoned -2
## 3 abandons -2
## 4 abducted -2
## 5 abduction -2
## 6 abductions -2
## 7 abhor -3
## 8 abhorred -3
## 9 abhorrent -3
## 10 abhors -3
## # ℹ 2,467 more rows
sentiment_rating <- tidy_review %>%
inner_join(afinn) %>%
select(app, word, value, rating) %>%
group_by(app) %>%
summarise(sentiment_score = mean(value, na.rm = TRUE),
rating_score = mean(rating, na.rm = TRUE))
## Joining with `by = join_by(word)`
sentiment_rating
## # A tibble: 5 × 3
## app sentiment_score rating_score
## <chr> <dbl> <dbl>
## 1 BingAI 0.951 3.36
## 2 DAVINCI 0.621 2.82
## 3 chatgpt 1.16 4.05
## 4 copilot 1.17 3.80
## 5 gemini 0.174 2.47
sentiment_rating <- ggplot(sentiment_rating, aes(x = sentiment_score, y = rating_score, label = app)) +
geom_point(size = 5, color = "steelblue") +
geom_text(vjust = -0.5, size = 4) +
labs(x = "Sentiment Score",
y = "Rating Score",
title = "Comparison of Average Sentiment Score and Rating by Generative AI App") +
theme_minimal() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 12),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
sentiment_rating
ggsave(filename = "Comparison of Average Sentiment Score and Rating by Generative AI App.png",
plot = sentiment_rating, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
ios_sentiment_rating <- tidy_review %>%
inner_join(afinn) %>%
select(app, word, value, rating, platform) %>%
group_by(app) %>%
filter(platform == "App Store") %>%
summarise(sentiment_score = mean(value, na.rm = TRUE),
rating_score = mean(rating, na.rm = TRUE))
## Joining with `by = join_by(word)`
ios_sentiment_rating
## # A tibble: 4 × 3
## app sentiment_score rating_score
## <chr> <dbl> <dbl>
## 1 BingAI 0.584 3.16
## 2 DAVINCI 0.616 2.81
## 3 chatgpt 0.938 3.93
## 4 copilot 0.789 3.42
ios_sentiment_rating <- ggplot(ios_sentiment_rating, aes(x = sentiment_score, y = rating_score, label = app)) +
geom_point(size = 5, color = "orange") +
geom_text(vjust = -0.5, size = 4) +
labs(x = "Sentiment Score",
y = "Rating Score",
title = "Comparison of Average Sentiment Score and Rating in APP store") +
theme_minimal() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 12),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
ios_sentiment_rating
ggsave(filename = "Comparison of Average Sentiment Score and Rating in APP store.png",
plot = ios_sentiment_rating, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
android_sentiment_rating <- tidy_review %>%
inner_join(afinn) %>%
select(app, word, value, rating, platform) %>%
group_by(app) %>%
filter(platform == "Google Play") %>%
summarise(sentiment_score = mean(value, na.rm = TRUE),
rating_score = mean(rating, na.rm = TRUE))
## Joining with `by = join_by(word)`
android_sentiment_rating
## # A tibble: 5 × 3
## app sentiment_score rating_score
## <chr> <dbl> <dbl>
## 1 BingAI 1.26 3.53
## 2 DAVINCI 2.33 5
## 3 chatgpt 1.85 4.43
## 4 copilot 1.64 4.26
## 5 gemini 0.174 2.47
android_sentiment_rating <- ggplot(android_sentiment_rating, aes(x = sentiment_score, y = rating_score, label = app)) +
geom_point(size = 5, color = "tomato") +
geom_text(vjust = -0.5, size = 4) +
labs(x = "Sentiment Score",
y = "Rating Score",
title = "Comparison of Average Sentiment Score and Rating in Google Play") +
theme_minimal() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 12),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
android_sentiment_rating
ggsave(filename = "Comparison of Average Sentiment Score and Rating in Google Play.png",
plot = android_sentiment_rating, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
sentiment_monthly <- tidy_review %>%
inner_join(afinn) %>%
mutate(date = floor_date(date, "month"),
date = format(date, "%Y-%m")) %>%
group_by(app, date) %>%
summarise(sentiment_score = mean(value, na.rm = TRUE)) %>%
ungroup()
## Joining with `by = join_by(word)`
## `summarise()` has grouped output by 'app'. You can override using the `.groups`
## argument.
sentiment_monthly
## # A tibble: 14 × 3
## app date sentiment_score
## <chr> <chr> <dbl>
## 1 BingAI 2024-01 0.727
## 2 BingAI 2024-02 0.558
## 3 BingAI 2024-03 1.14
## 4 DAVINCI 2024-01 -0.0208
## 5 DAVINCI 2024-02 -0.0154
## 6 DAVINCI 2024-03 1.31
## 7 chatgpt 2024-01 1.06
## 8 chatgpt 2024-02 0.801
## 9 chatgpt 2024-03 1.49
## 10 copilot 2023-12 0.657
## 11 copilot 2024-01 0.473
## 12 copilot 2024-02 0.751
## 13 copilot 2024-03 1.37
## 14 gemini 2024-03 0.174
sentiment_monthly <- ggplot(sentiment_monthly, aes(x = as.Date(paste0(date, "-01")),
y = sentiment_score)) +
geom_line(aes(color = app), linewidth = 1.2, show.legend = F) +
geom_point(aes(color = app), size = 3, show.legend = F) +
facet_wrap(~ app, , scales = "free", ncol = 3) +
scale_x_date(date_breaks = "1 month",
date_labels = "%Y-%m") +
scale_color_manual(values = c(
"chatgpt" = "#ab68ff",
"copilot" = "#09AA6C",
"BingAI" = "#ffb900",
"DAVINCI" = "#0970E9",
"gemini" = "#CA6673")) +
labs(
title = "Monthly sentiment score changes by Generative AI app",
x = "month",
y = "sentiment score"
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(face = "bold", hjust = 0.5, size = 12),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
sentiment_monthly
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
ggsave(filename = "Monthly sentiment score changes by Generative AI app.png",
plot = sentiment_monthly, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
To gain a more detailed understanding of the specific emotions and evaluations users had for each Generative AI app, I compared the top 10 sentiment words used in the reviews of each app.
For visualization, since there were several apps, I used facet_wrap with free scales to examine the distribution of sentiment words within each app. I adjusted the margins for readability, hid the legend, and sorted the bars by frequency so that the results could be easily interpreted. I also used distinctive brand colors for each app and arranged the graphs in order of rating score to avoid confusion.
The analysis revealed that for ChatGPT, “love” was the most frequently used sentiment word, with “helpful” and “help” also ranking highly, suggesting that users found the app very useful in their work. However, “wrong” also appeared among the top ten, indicating that negative experiences were present as well. Copilot also had “love” as the most frequent sentiment word, with many positive words overall, but “wrong” was again among the top ten. For BingAI, “love” was the most common, and other positive words such as “nice,” “amazing,” “awesome,” “helpful,” and “excellent” were also prominent, with no negative sentiment words among the top ten. DaVinci’s reviews included both positive and negative words, such as “limited” and “waste.” In contrast, Gemini’s top sentiment words included more negative terms like “useless,” “worse,” and “bad,” which may be because reviews were collected only a month after its release, when users were more likely to report dissatisfaction. These findings can also be related to the earlier comparison of sentiment and rating scores. Copilot had a higher sentiment score than ChatGPT, and both had many positive sentiment words, but ChatGPT’s rating score was higher. This may be due to ChatGPT’s reputation as an innovative generative AI, which could have influenced users’ expectations and ratings. Overall, while sentiment analysis provided insight into user perceptions, the limitations of the data—such as uneven review distribution by platform and time—mean that the results should be interpreted with care.
ai_sentiment <- tidy_review %>%
inner_join(afinn) %>%
count(app, word, sort = TRUE) %>%
group_by(app) %>%
slice_max(n, n = 10, with_ties = FALSE) %>%
ungroup()
## Joining with `by = join_by(word)`
ai_sentiment
## # A tibble: 50 × 3
## app word n
## <chr> <chr> <int>
## 1 BingAI love 65
## 2 BingAI nice 54
## 3 BingAI rewards 46
## 4 BingAI amazing 30
## 5 BingAI easy 28
## 6 BingAI awesome 24
## 7 BingAI excellent 22
## 8 BingAI helpful 22
## 9 BingAI free 21
## 10 BingAI fun 21
## # ℹ 40 more rows
ai_sentiment$app <- factor(ai_sentiment$app, levels = c("chatgpt", "copilot", "BingAI", "DAVINCI", "gemini"))
ai_sentiment <- ggplot(ai_sentiment, aes(x = reorder_within(word, n, app), y = n, fill = app)) +
geom_col(show.legend = FALSE) +
facet_wrap(~ app, scales = "free", ncol = 3) +
scale_x_reordered() +
coord_flip() +
scale_fill_manual(values = c(
"chatgpt" = "#ab68ff",
"copilot" = "#09AA6C",
"BingAI" = "#ffb900",
"DAVINCI" = "#0970E9",
"gemini" = "#CA6673")) +
labs(title = "Comparison of sentiment words by Generative AI apps", x = "Word", y = "Count") +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
ai_sentiment
ggsave(filename = "Comparison of sentiment words by Generative AI apps.png",
plot = ai_sentiment, width = 12, height = 8, dpi = 300, units = "in", bg = "white")
To address the second research question, a tf-idf analysis was conducted to identify words that are rare across all reviews but frequent within each app’s reviews. Since the dataset included multiple documents (apps), tf-idf was chosen over log odds ratio. Stop words and irrelevant terms (e.g., contractions like it’s, I’m) were filtered out before visualization.
Due to the number of apps, facet_wrap was used with free scales instead of a shared y-axis to examine the distribution of tf-idf words within each app. To enhance readability, margins were adjusted, legends were hidden, and labels were angled to prevent overlap caused by long tf-idf values (up to three decimal places). Bars were sorted by frequency for quick interpretation. Each app was assigned a distinct color based on its brand identity to improve differentiation. The graphs were ordered by the apps’ rating scores, consistent with the sentiment analysis, to minimize confusion.
App names themselves frequently appear as top words due to review context. However, for BingAI, the term copilot was also prominent, suggesting a strong association. This aligns with the fact that both BingAI and Copilot are Microsoft products. The presence of microsoft among BingAI’s top tf-idf words further supports this, especially after Microsoft rebranded Bing as “Microsoft Copilot” in November 2023. In the case of ChatGPT, words such as ‘question’, ‘answer’, ‘school’, ‘essay’, and ‘custom’ were frequently extracted. From this, it can be inferred that users are utilizing AI functions in a question-and-answer format and mainly using ChatGPT for essay writing. As for ‘custom’ and ‘log’, since they are often used with multiple meanings, more detailed analysis is required. In the case of Copilot, similar to Bing, words related to its developer, such as ‘Microsoft’ and ‘365’, were extracted as top-ranking terms. Words like ‘chat’ and ‘gpt’ also appeared frequently, indicating that Copilot is often mentioned alongside ChatGPT. In fact, it was observed that many data/IT-related platforms such as DataNorth, DataCamp, and A-Zapier have published content comparing Copilot and ChatGPT. Similar to ChatGPT, the frequent appearance of ‘questions’ and ‘answer’ suggests that it is also used in a Q&A format. In addition, the frequent use of the word ‘create’ implies that Copilot is also utilized for content generation. For Bing, words like ‘rewards’, ‘earn’, and ‘receipt’ were frequently extracted. This is likely due to the ‘Bing Deal’ feature, which allows users to scan receipts to receive paybacks. It was also confirmed that a significant number of videos related to receipt scanning using Bing have been uploaded on TikTok. Since terms like ‘receipts’ and ‘notifications’ can be used in various contexts, further in-depth analysis is needed. In the case of DaVinci, the word ‘tattoo’ was among the top-ranked terms, which can be attributed to DaVinci’s tattoo design feature. Additionally, the frequent use of words such as ‘avatars’, ‘styles’, ‘create’, and ‘artwork’ once again confirms DaVinci’s specialization in generating artistic content. Since the word ‘trial’ can also be used in various situations, additional analysis is required. For Gemini, words like ‘assistant’ and ‘Google’s’ were extracted as high-frequency terms. This is likely because, after installing the Gemini app, it takes over functions previously provided by Google Assistant, such as voice commands, schedule management, and information search. As a result, the two are frequently mentioned together. Words like ‘reminders’ and ‘replace’ were also likely to be extracted for this reason. Additionally, ‘Spotify’ and ‘song’ appeared often, which can be explained by the fact that Gemini is linked with the Spotify app, allowing users to play music via voice commands.
ai_tf_idf <- tidy_review %>%
count(app, word, sort = T) %>%
bind_tf_idf(term = word,
document = app,
n = n) %>%
mutate(word_clean = tolower(
str_replace_all(word, "['’‘`]", "") %>%
str_replace_all("[[:punct:]]", "")
)) %>%
filter(!word_clean %in% c("im", "its", "ive", "aaaaaaaaaaaaaaa")) %>%
group_by(app) %>%
arrange(desc(tf_idf)) %>%
slice_max(tf_idf, n = 10, with_ties = F)
ai_tf_idf
## # A tibble: 50 × 7
## # Groups: app [5]
## app word n tf idf tf_idf word_clean
## <chr> <chr> <int> <dbl> <dbl> <dbl> <chr>
## 1 BingAI rewards 46 0.00625 0.916 0.00573 rewards
## 2 BingAI bing 161 0.0219 0.223 0.00488 bing
## 3 BingAI earn 18 0.00245 0.916 0.00224 earn
## 4 BingAI tabs 10 0.00136 1.61 0.00219 tabs
## 5 BingAI receipt 9 0.00122 1.61 0.00197 receipt
## 6 BingAI receipts 9 0.00122 1.61 0.00197 receipts
## 7 BingAI reward 15 0.00204 0.916 0.00187 reward
## 8 BingAI copilot 61 0.00829 0.223 0.00185 copilot
## 9 BingAI microsoft 59 0.00802 0.223 0.00179 microsoft
## 10 BingAI notifications 14 0.00190 0.916 0.00174 notifications
## # ℹ 40 more rows
ai_tf_idf$app <- factor(ai_tf_idf$app, levels = c("chatgpt", "copilot", "BingAI", "DAVINCI", "gemini"))
ai_tf_idf <- ggplot(ai_tf_idf, aes(x = reorder_within(word, tf_idf, app),
y = tf_idf,
fill = app)) +
geom_col(width = 0.7, show.legend = F) +
coord_flip() +
facet_wrap(~ app, scales = "free", ncol = 3) +
scale_x_reordered() +
scale_fill_manual(values = c(
"chatgpt" = "#ab68ff",
"copilot" = "#09AA6C",
"BingAI" = "#ffb900",
"DAVINCI" = "#0970E9",
"gemini" = "#CA6673")) +
labs(title = "Top 10 words in tf-idf by Generative AI App",
x = "Words", y = "tf-idf") +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
ai_tf_idf
ggsave("Top 10 words in tf-idf by Generative AI App.png",
plot = ai_tf_idf, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
As discussed above, TF-IDF allowed for a simple identification of the characteristics of each app, but it was sometimes difficult to understand the precise context in which certain words were used. To analyze the perceived features of each app in more detail, bigram analysis was conducted. Since bigrams capture two words used consecutively, they are more useful in understanding contextual meaning.
Initially, each app’s name appeared so frequently that bigram networks were formed mainly around those names. Therefore, the app names were removed prior to building the bigram networks. To ensure readability and preserve sufficient information for each app, a frequency filter was applied: 10 for ChatGPT, 5 for Copilot, and 4 for Bing, DaVinci, and Gemini. A similar number of bigrams was extracted for each app with these settings. Relatively more bigrams were observed in Copilot and ChatGPT, which is likely due to the larger number of total reviews for these two apps, as previously confirmed. To avoid confusion, brand colors were used for each app in the graphs, as applied above, and care was taken to prevent overlapping between words and nodes to improve readability. Additionally, the edges were darkened according to frequency, making the results easier to interpret.
For Chatgpt, the context of the word ‘custom’, which was previously unclear, was clarified. The term ‘custom instructions’ was frequently used in reviews, suggesting that users recognize the feature that allows them to inform ChatGPT of their preferences, roles, and desired answer formats in advance, so that responses are tailored accordingly in future conversations. Also, frequent use of terms like ‘paid version’ and ‘free version’ indicates user awareness of differences between subscription plans. Moreover, phrases such as ‘real time’ and ‘images generate’ show that users perceive real-time responses and image generation features as notable aspects. Positive evaluations were also evident, with frequent bigrams like ‘user friendly’, ‘game changer’, and ‘highly recommend’.
For Copilot, bigrams such as ‘create images’, ‘image generation’, and ‘search results’ were widely used, indicating core functionalities of Copilot like image creation and information retrieval. Compared to other generative AI apps like ChatGPT, Gemini, or Bing—which are not primarily focused on image creation—Copilot had more image-related bigrams, suggesting that users actively use it for generating images. Furthermore, as Copilot is integrated with the Bing search engine and allows real-time information retrieval, it is reasonable to assume that bigrams like ‘search engine’ appeared frequently. Like ChatGPT, positive expressions such as ‘user friendly’, ‘highly recommend’, and ‘game changer’ were also commonly found.
For Bing, the frequent extraction of the term ‘search engine’ indicates that users mainly use Bing for information retrieval. The mention of ‘edge app’ also appeared often, reflecting Bing’s integration with the Edge browser. Bigrams such as ‘microsoft rewards’ and ‘gift card’ refer to app-based incentive features. Through the BingAI app, users can earn points from Microsoft by performing searches, which can be redeemed for various gift cards. This suggests that users perceive Bing not only as an AI app but also as a broader platform including reward-based utility features.
For DaVinci, as expected, many bigrams were related to image and design generation, confirming DaVinci’s focus on artistic content creation. Bigrams such as ‘tattoo ideas’, ‘AI art’, and ‘image generator’ were frequently found. DaVinci was also mentioned alongside another image-generation AI system, ‘Mid Journey’. Compared to other apps, there were more references to pricing plans, including bigrams like ‘free version’, ‘pro version’, ‘daily limit’, ‘yearly subscription’, ‘free trial’, and ‘don’t waste’. These reflect user awareness of DaVinci’s limitations, such as image generation quotas even under paid plans and restrictions in the free version. This may also explain the relatively lower user ratings for DaVinci.
For Gemini, the most frequently used term was ‘Google Assistant’, and many bigrams were related to assistant functions and user satisfaction, such as ‘voice commands’, ‘hands free’, ‘hey Google’, ‘set reminders’, and ‘lock screen’. The bigram ‘forever takes’ was also extracted, indicating dissatisfaction; this aligns with blog reviews at the time that complained Gemini’s AI note-taking feature was very slow to respond. This could be one of the reasons for Gemini’s lower rating and sentiment scores, as observed earlier. Although Gemini also provides information search features, the majority of extracted bigrams were related to basic mobile assistant functions, suggesting that users primarily perceived Gemini as an assistant-like service during the analysis period.
#Chat GPT
chatgpt_bigram <- review_clean %>%
filter(app == "chatgpt") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "chatgpt"),
!word2 %in% c("br", stop_words$word, "chatgpt")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(n >= 10) %>%
graph_from_data_frame()
chatgpt_bigram
## IGRAPH 56b03d6 DN-- 34 24 --
## + attr: name (v/c), n (e/n)
## + edges from 56b03d6 (vertex names):
## [1] chat ->gpt nice ->app voice ->chat
## [4] 5 ->stars game ->changer highly ->recommend
## [7] gpt ->4 free ->version ai ->app
## [10] real ->time user ->friendly amazing ->app
## [13] app ->it’s helpful ->app absolutely->love
## [16] love ->chat custom ->instructions generate ->images
## [19] 5 ->star app ->i’ve excellent ->app
## [22] it’s ->amazing mind ->blowing paid ->version
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
chatgpt_bigram <- ggraph(chatgpt_bigram, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#ab68ff", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
labs(title = "Bigram analysis of ChatGPT") +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
chatgpt_bigram
ggsave("Bigram analysis of ChatGPT.png",
plot = chatgpt_bigram, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
#Copilot
copilot_bigram <- review_clean %>%
filter(app == "copilot") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "copilot"),
!word2 %in% c("br", stop_words$word, "copilot")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(n >= 5)
copilot_bigram
## word1 word2 n
## 1 ai app 26
## 2 chat gpt 26
## 3 gpt 4 24
## 4 create images 18
## 5 user friendly 11
## 6 image generation 9
## 7 5 stars 8
## 8 amazing app 8
## 9 chat history 8
## 10 chatgpt app 8
## 11 highly recommend 8
## 12 nice app 8
## 13 search engine 8
## 14 ai tool 7
## 15 artificial intelligence 7
## 16 bing app 7
## 17 game changer 7
## 18 image creation 7
## 19 image generator 7
## 20 24 hours 6
## 21 absolutely love 6
## 22 bing chat 6
## 23 search results 6
## 24 ai assistant 5
## 25 app store 5
## 26 chatgpt 4 5
## 27 excellent app 5
## 28 generating images 5
## 29 google search 5
## 30 internet connection 5
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
copilot_bigram <- ggraph(copilot_bigram, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#09AA6C", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
labs(title = "Bigram analysis of Copilot") +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
copilot_bigram
ggsave("Bigram analysis of Copilot.png",
plot = copilot_bigram, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
#BingAI
bing_bigram <- review_clean %>%
filter(app == "BingAI") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "BingAI"),
!word2 %in% c("br", stop_words$word, "BingAI")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(n >= 4)
bing_bigram
## word1 word2 n
## 1 search engine 19
## 2 bing app 18
## 3 nice app 18
## 4 5 stars 11
## 5 bing chat 11
## 6 chat gpt 9
## 7 image creator 8
## 8 ai chat 7
## 9 gpt 4 7
## 10 love bing 7
## 11 bing ai 6
## 12 image generator 6
## 13 microsoft rewards 6
## 14 search results 6
## 15 ai image 5
## 16 excellent app 5
## 17 search engines 5
## 18 ai app 4
## 19 copilot feature 4
## 20 duty 4 4
## 21 edge app 4
## 22 gift card 4
## 23 gift cards 4
## 24 search box 4
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
BingAI_bigram <- ggraph(bing_bigram, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#ffb900", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
labs(title = "Bigram analysis of BingAI") +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
BingAI_bigram
ggsave("Bigram analysis of BingAIt.png",
plot = BingAI_bigram, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
#DaVinci
davinci_bigram <- review_clean %>%
filter(app == "DAVINCI") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "DAVINCI"),
!word2 %in% c("br", stop_words$word, "DAVINCI")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(n >= 4)
davinci_bigram
## word1 word2 n
## 1 free trial 37
## 2 daily limit 12
## 3 3 day 10
## 4 don’t waste 9
## 5 fun fun 9
## 6 ai image 8
## 7 50 images 7
## 8 ai art 7
## 9 da vinci 7
## 10 free version 7
## 11 mid journey 7
## 12 da vinci's 6
## 13 day free 6
## 14 image generator 6
## 15 tattoo ideas 6
## 16 5 minutes 5
## 17 awesome app 5
## 18 day trial 5
## 19 multiple times 5
## 20 yearly subscription 5
## 21 5 stars 4
## 22 absolutely love 4
## 23 ai apps 4
## 24 app doesn’t 4
## 25 can’t spell 4
## 26 pretty cool 4
## 27 pro version 4
## 28 unlimited images 4
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
davinci_bigram <- ggraph(davinci_bigram, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#0970E9", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
labs(title = "Bigram analysis of DaVinci") +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
davinci_bigram
ggsave("Bigram analysis of DaVinci.png",
plot = davinci_bigram, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
#gemini
gemini_bigram <- review_clean %>%
filter(app == "gemini") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "gemini", "aaaaaaaaaaaaaaa"),
!word2 %in% c("br", stop_words$word, "gemini", "aaaaaaaaaaaaaaa")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(n >= 4)
gemini_bigram
## word1 word2 n
## 1 google assistant 140
## 2 replace google 14
## 3 replace assistant 12
## 4 google home 8
## 5 play music 8
## 6 hey google 6
## 7 previous google 6
## 8 set reminders 6
## 9 simple tasks 6
## 10 ai tool 5
## 11 assistant features 5
## 12 pixel 8 5
## 13 8 pro 4
## 14 ai app 4
## 15 assistant multiple 4
## 16 basic tasks 4
## 17 default assistant 4
## 18 google search 4
## 19 hands free 4
## 20 lock screen 4
## 21 original assistant 4
## 22 pixel 6 4
## 23 regular google 4
## 24 takes forever 4
## 25 voice commands 4
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
gemini_bigram <- ggraph(gemini_bigram, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#CA6673", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
labs(title = "Bigram analysis of Gemini") +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
gemini_bigram
ggsave("Bigram analysis of Gemini.png",
plot = gemini_bigram, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
Through the previous sentiment analysis, TF-IDF, and bigram analysis, we examined how satisfied users are with each app and which features they perceive as most significant. Now, we aim to combine these analyses to investigate which aspects of each app are evaluated positively or negatively by users. To achieve this, bigram networks were created by filtering for positive sentiment words such as “helpful” and “nice,” and negative ones like “bad” and “limited” from each app’s bigram table. Although the goal was to use “helpful” and “bad” as standard sentiment words across all apps for objective comparison, meaningful bigram results could not be secured for every app due to variations in expression. Therefore, we conducted test runs with alternative words for each app and selected the most meaningful positive and negative sentiment words accordingly.
To ensure readability and facilitate comparative analysis, the bigram networks related to positive and negative sentiment words were placed side by side.
Words such as tool, information, fast, suggestion, and advice were frequently used together with helpful. This suggests that users perceive ChatGPT as an app that provides convenient and useful information and functions. #### ChatGPT (bad) Words like gateway and rewriting were frequently used with bad. Many online reviews have reported “bad gateway” errors, and the term rewriting may reflect limitations in the app’s ability to properly revise text or incorporate user feedback during content generation.
Words such as answers, resource, results, and tool appeared often with helpful. This implies that users recognize Copilot as a search engine that provides especially useful information. #### Copilot (bad) Words such as attitude, feels, and reskin were often used with bad. This suggests that users may not perceive significant improvements or functional differences from Microsoft’s previous AI products, resulting in negative emotional responses during use.
Words like search, art, picture, and easy frequently appeared with nice. This indicates that Bing is performing well in terms of information delivery and image generation. #### Bing (bad) Words such as experience and search were used with bad, revealing that some users also have negative evaluations of Bing’s search function. Additionally, the appearance of economy in negative contexts suggests that some users may feel dissatisfaction with Bing’s reward-related features.
Words like art, artwork, picture, and quality appeared with amazing, showing that users are highly satisfied with the quality of DaVinci’s image generation capabilities. #### DaVinci (limited) The word amount was most frequently used with limited, confirming that limitations on usage frequency, as seen in the bigram analysis, are negatively perceived by users.
Due to the low number of reviews and extracted bigrams, it was difficult to derive meaningful results. However, some evidence suggests that users have a generally positive perception of the app. #### Gemini (useless) Similarly, although meaningful results could not be derived due to the small volume of data, negative perceptions of the app were also present.
#helpful
chatgpt_helpful <- review_clean %>%
filter(app == "chatgpt") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "chatgpt"),
!word2 %in% c("br", stop_words$word, "chatgpt")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "helpful") %>%
graph_from_data_frame()
chatgpt_helpful
## IGRAPH 5b93dd7 DN-- 20 20 --
## + attr: name (v/c), n (e/n)
## + edges from 5b93dd7 (vertex names):
## [1] helpful->app helpful->tool helpful->responses
## [4] helpful->application helpful->advice helpful->ai
## [7] helpful->alot helpful->apps helpful->fast
## [10] helpful->feature helpful->helpful helpful->information
## [13] helpful->it’s helpful->life helpful->lonely
## [16] helpful->love helpful->person helpful->solve
## [19] helpful->suggestions helpful->till
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
chatgpt_helpful_graph <- ggraph(chatgpt_helpful, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#ab68ff", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
#bad
chatgpt_bad <- review_clean %>%
filter(app == "chatgpt") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "chatgpt"),
!word2 %in% c("br", stop_words$word, "chatgpt")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "bad") %>%
graph_from_data_frame()
chatgpt_bad
## IGRAPH 5bf8551 DN-- 16 15 --
## + attr: name (v/c), n (e/n)
## + edges from 5bf8551 (vertex names):
## [1] bad->gateway bad->reviews bad->ad bad->ai
## [5] bad->answer bad->constantly bad->day bad->experience
## [9] bad->fast bad->game bad->giving bad->platform
## [13] bad->reasoning bad->rewriting bad->words
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
chatgpt_bad_graph <- ggraph(chatgpt_bad, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#ab68ff", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
chatgpt_centered <- chatgpt_helpful_graph + chatgpt_bad_graph +
plot_annotation(
title = "Bigrams Centered on 'Helpful' and 'Bad' in ChatGPT Reviews",
theme = theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20)
)
)
chatgpt_centered
ggsave("Bigrams Centered on 'Helpful' and 'Bad' in ChatGPT Reviews.png",
plot = chatgpt_centered, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
#helpful
copilot_helpful <- review_clean %>%
filter(app == "copilot") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "copilot"),
!word2 %in% c("br", stop_words$word, "copilot")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "helpful") %>%
graph_from_data_frame()
copilot_helpful
## IGRAPH 5ce483c DN-- 12 11 --
## + attr: name (v/c), n (e/n)
## + edges from 5ce483c (vertex names):
## [1] helpful->application helpful->app helpful->resource
## [4] helpful->answers helpful->assistant helpful->easy
## [7] helpful->images helpful->love helpful->results
## [10] helpful->software helpful->tool
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
copilot_helpful_graph <- ggraph(copilot_helpful, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#09AA6C", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
#bad
copilot_bad <- review_clean %>%
filter(app == "copilot") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "copilot"),
!word2 %in% c("br", stop_words$word, "copilot")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "bad") %>%
graph_from_data_frame()
copilot_bad
## IGRAPH 5d1a8f6 DN-- 7 6 --
## + attr: name (v/c), n (e/n)
## + edges from 5d1a8f6 (vertex names):
## [1] bad->attitude bad->business bad->feature bad->feels bad->microsoft
## [6] bad->reskin
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
copilot_bad_graph <- ggraph(copilot_bad, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#09AA6C", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
copilot_centered <- copilot_helpful_graph + copilot_bad_graph +
plot_annotation(
title = "Bigrams Centered on 'Helpful' and 'Bad' in copilot Reviews",
theme = theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20)
)
)
copilot_centered
ggsave("Bigrams Centered on 'Helpful' and 'Bad' in copilot Reviews.png",
plot = copilot_centered, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
#nice
BingAI_nice <- review_clean %>%
filter(app == "BingAI") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "BingAI"),
!word2 %in% c("br", stop_words$word, "BingAI")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "nice") %>%
graph_from_data_frame()
BingAI_nice
## IGRAPH 5db6cc3 DN-- 12 11 --
## + attr: name (v/c), n (e/n)
## + edges from 5db6cc3 (vertex names):
## [1] nice->app nice->ai nice->amount nice->application
## [5] nice->art nice->cool nice->easy nice->hai
## [9] nice->pic nice->search nice->set
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
BingAI_nice_graph <- ggraph(BingAI_nice, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#ffb900", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
#bad
BingAI_bad <- review_clean %>%
filter(app == "BingAI") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "BingAI"),
!word2 %in% c("br", stop_words$word, "BingAI")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "bad") %>%
graph_from_data_frame()
BingAI_bad
## IGRAPH 5dd3b79 DN-- 7 6 --
## + attr: name (v/c), n (e/n)
## + edges from 5dd3b79 (vertex names):
## [1] bad->app bad->experience bad->search bad->broken
## [5] bad->economy bad->people
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
BingAI_bad_graph <- ggraph(BingAI_bad, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#ffb900", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
BingAI_centered <- BingAI_nice_graph + BingAI_bad_graph +
plot_annotation(
title = "Bigrams Centered on 'Nice' and 'Bad' in BingAI Reviews",
theme = theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 12),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20)
)
)
BingAI_centered
ggsave("Bigrams Centered on 'Nice' and 'Bad' in BingAI Reviews.png",
plot = BingAI_centered, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
#amazing
DaVinci_amazing <- review_clean %>%
filter(app == "DAVINCI") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "DAVINCI"),
!word2 %in% c("br", stop_words$word, "DAVINCI")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "amazing") %>%
graph_from_data_frame()
DaVinci_amazing
## IGRAPH 5e67598 DN-- 11 10 --
## + attr: name (v/c), n (e/n)
## + edges from 5e67598 (vertex names):
## [1] amazing->app amazing->art amazing->artwork amazing->degree
## [5] amazing->easy amazing->hug amazing->images amazing->photo
## [9] amazing->picture amazing->quality
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
DaVinci_amazing_graph <- ggraph(DaVinci_amazing, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#0970E9", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
#limited
DaVinci_limited <- review_clean %>%
filter(app == "DAVINCI") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "DAVINCI"),
!word2 %in% c("br", stop_words$word, "DAVINCI")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "limited") %>%
graph_from_data_frame()
DaVinci_limited
## IGRAPH 5e88cd0 DN-- 5 4 --
## + attr: name (v/c), n (e/n)
## + edges from 5e88cd0 (vertex names):
## [1] limited->amount limited->50 limited->daily limited->picture
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
DaVinci_limited_graph <- ggraph(DaVinci_limited, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#0970E9", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
DaVinci_centered <- DaVinci_amazing_graph + DaVinci_limited_graph +
plot_annotation(
title = "Bigrams Centered on 'Amazing' and 'Limited' in DaVinci Reviews",
theme = theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20)
)
)
DaVinci_centered
ggsave("Bigrams Centered on 'Amazing' and 'Limited' in DaVinci Reviews.png",
plot = DaVinci_centered, width = 10, height = 6, dpi = 300, units = "in", bg = "white")
#helpful
gemini_helpful <- review_clean %>%
filter(app == "gemini") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "gemini"),
!word2 %in% c("br", stop_words$word, "gemini")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "helpful") %>%
graph_from_data_frame()
gemini_helpful
## IGRAPH 5f15036 DN-- 3 2 --
## + attr: name (v/c), n (e/n)
## + edges from 5f15036 (vertex names):
## [1] helpful->ai helpful->software
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
gemini_helpful_graph <- ggraph(gemini_helpful, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#CA6673", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
#useless
gemini_useless <- review_clean %>%
filter(app == "DAVINCI") %>%
unnest_tokens(input = review_description,
output = bigram,
token = "ngrams",
n = 2) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% c("br", stop_words$word, "gemini"),
!word2 %in% c("br", stop_words$word, "gemini")) %>%
count(word1, word2, sort = T) %>%
na.omit() %>%
filter(word1 == "useless") %>%
graph_from_data_frame()
gemini_useless
## IGRAPH 5f3235c DN-- 2 1 --
## + attr: name (v/c), n (e/n)
## + edge from 5f3235c (vertex names):
## [1] useless->app
set.seed(2023)
a <- grid::arrow(type = "closed", length = unit(.15, "inches"))
gemini_useless_graph <- ggraph(gemini_useless, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = a, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "#CA6673", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1, repel = T) +
theme_void() +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20))
gemini_centered <- gemini_helpful_graph + gemini_useless_graph +
plot_annotation(
title = "Bigrams Centered on 'Helpful' and 'Useless' in gemini Reviews",
theme = theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.margin = margin(t = 20, r = 20, b = 20, l = 20)
)
)
gemini_centered
ggsave("Bigrams Centered on 'Helpful' and 'Useless' in gemini Reviews.png",
plot = gemini_centered, width = 10, height = 6, dpi = 300, units = "in", bg = "white")