<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/modeling-airbnb-prices/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://www.mango-solutions.com/blog/modeling-airbnb-prices"> RBlog – Mango Solutions</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>In this post we’re going to model the prices of Airbnb appartments in London. In other words, the aim is to build our own price suggestion model. We will be using data from <a rel="nofollow" href="http://insideairbnb.com/" target="_blank">http://insideairbnb.com/</a> which we collected in April 2018. This work is inspired from the <a rel="nofollow" href="https://d1no007.github.io/OptiBnB/" target="_blank">Airbnb price prediction model </a>built by Dino Rodriguez, Chase Davis, and Ayomide Opeyemi. Normally we would be doing this in R but we thought we’d try our hand at Python for a change.</p>
<p>We present a shortened version here, but the full version is available on our <a rel="nofollow" href="https://github.com/MangoTheCat/Modelling-Airbnb-Prices/tree/reproduce-results" target="_blank">GitHub</a>.</p>
<h2>Data Preprocessing</h2>
<p>First, we import the listings gathered in the csv file.</p>
<pre><code><span>import</span> pandas <span>as</span> pd
listings_file_path = <span>'listings.csv.gz'</span> 
listings = pd.read_csv(listings_file_path, compression=<span>&quot;gzip&quot;</span>, low_memory=<span>False</span>)
listings.columns</code></pre>
<pre><code>Index(['id', 'listing_url', 'scrape_id', 'last_scraped', 'name', 'summary',
       'space', 'description', 'experiences_offered', 'neighborhood_overview',
       'notes', 'transit', 'access', 'interaction', 'house_rules',
       'thumbnail_url', 'medium_url', 'picture_url', 'xl_picture_url',
       'host_id', 'host_url', 'host_name', 'host_since', 'host_location',
       'host_about', 'host_response_time', 'host_response_rate',
       'host_acceptance_rate', 'host_is_superhost', 'host_thumbnail_url',
       'host_picture_url', 'host_neighbourhood', 'host_listings_count',
       'host_total_listings_count', 'host_verifications',
       'host_has_profile_pic', 'host_identity_verified', 'street',
       'neighbourhood', 'neighbourhood_cleansed',
       'neighbourhood_group_cleansed', 'city', 'state', 'zipcode', 'market',
       'smart_location', 'country_code', 'country', 'latitude', 'longitude',
       'is_location_exact', 'property_type', 'room_type', 'accommodates',
       'bathrooms', 'bedrooms', 'beds', 'bed_type', 'amenities', 'square_feet',
       'price', 'weekly_price', 'monthly_price', 'security_deposit',
       'cleaning_fee', 'guests_included', 'extra_people', 'minimum_nights',
       'maximum_nights', 'calendar_updated', 'has_availability',
       'availability_30', 'availability_60', 'availability_90',
       'availability_365', 'calendar_last_scraped', 'number_of_reviews',
       'first_review', 'last_review', 'review_scores_rating',
       'review_scores_accuracy', 'review_scores_cleanliness',
       'review_scores_checkin', 'review_scores_communication',
       'review_scores_location', 'review_scores_value', 'requires_license',
       'license', 'jurisdiction_names', 'instant_bookable',
       'cancellation_policy', 'require_guest_profile_picture',
       'require_guest_phone_verification', 'calculated_host_listings_count',
       'reviews_per_month'],
      dtype='object')</code></pre>
<p>The data has 95 columns or features. Our first step is to perform feature selection to reduce this number.</p>
<h3>Feature selection</h3>
<h4>Selection on Missing Data</h4>
<p>Features that have a high number of missing values aren’t useful for our model so we should remove them.</p>
<pre><code><span>import</span> matplotlib.pyplot <span>as</span> plt
%matplotlib inline

percentage_missing_data = listings.isnull().sum() / listings.shape[<span>0</span>]
ax = percentage_missing_data.plot(kind = <span>'bar'</span>, color=<span>'#E35A5C'</span>, figsize = (<span>16</span>, <span>5</span>))
ax.set_xlabel(<span>'Feature'</span>)
ax.set_ylabel(<span>'Percent Empty / NaN'</span>)
ax.set_title(<span>'Feature Emptiness'</span>)
plt.show()</code></pre>
<div><a rel="nofollow" href="https://i1.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_10_0.png?ssl=1" target="_blank"><img sizes="(max-width: 947px) 100vw, 947px" src="https://i1.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_10_0.png?w=450&ssl=1" alt="" class="wp-image-6271" data-recalc-dims="1"></a></div>
<p>As we can see, the features <code>neighbourhood_group_cleansed</code>, <code>square_feet</code>, <code>has_availability</code>, <code>license</code> and <code>jurisdiction_names</code> mostly have missing values. The features <code>neighbourhood</code>, <code>cleaning_fee</code> and <code>security_deposit</code> are more than 30% empty which is too much in our opinion. The <code>zipcode</code> feature also has some missing values but we can either remove these values or impute them within reasonable accuracy.</p>
<pre><code>useless = [<span>'neighbourhood'</span>, <span>'neighbourhood_group_cleansed'</span>, <span>'square_feet'</span>, <span>'security_deposit'</span>, <span>'cleaning_fee'</span>, 
           <span>'has_availability'</span>, <span>'license'</span>, <span>'jurisdiction_names'</span>]
listings.drop(useless, axis=<span>1</span>, inplace=<span>True</span>)</code></pre>

<div>
<h4>Selection on Sparse Categorical Features</h4>
<p>Let’s have a look at the categorical data to see the number of unique values.</p>
<pre><code>categories = listings.columns[listings.dtypes == <span>'object'</span>]
percentage_unique = listings[categories].nunique() / listings.shape[<span>0</span>]

ax = percentage_unique.plot(kind = <span>'bar'</span>, color=<span>'#E35A5C'</span>, figsize = (<span>16</span>, <span>5</span>))
ax.set_xlabel(<span>'Feature'</span>)
ax.set_ylabel(<span>'Percent # Unique'</span>)
ax.set_title(<span>'Feature Emptiness'</span>)
plt.show()</code></pre>
<div><a rel="nofollow" href="https://i0.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_14_0.png?ssl=1" target="_blank"><img sizes="(max-width: 947px) 100vw, 947px" src="https://i0.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_14_0.png?w=450&ssl=1" alt="" class="wp-image-6272" data-recalc-dims="1"></a></div>
<p>We can see that the <code>street</code> and <code>amenities</code> features have a large number of unique values. It would require some natural language processing to properly wrangle these into useful features. We believe we have enough location information with <code>neighbourhood_cleansed</code> and <code>zipcode</code> so we’ll remove <code>street</code>. We also remove <code>amenities</code>, <code>calendar_updated</code> and <code>calendar_last_updated</code> features as these are too complicated to process for the moment.</p>
<pre><code>to_drop = [<span>'street'</span>, <span>'amenities'</span>, <span>'calendar_last_scraped'</span>, <span>'calendar_updated'</span>]
listings.drop(to_drop, axis=<span>1</span>, inplace=<span>True</span>)</code></pre>
<p>Now, let’s have a look at the <code>zipcode</code> feature. The above visualisation shows us that there are lots of different postcodes, maybe too many?</p>
<pre><code>print(<span>&quot;Number of Zipcodes:&quot;</span>, listings[<span>'zipcode'</span>].nunique())</code></pre>
<pre><code>Number of Zipcodes: 24774</code></pre>
<p>Indeed, there are too many zipcodes. If we leave this feature as is it might cause overfitting. Instead, we can regroup the postcodes. At the moment, they are separated as in the following example: KT1 1PE. We’ll keep the first part of the zipcode (e.g. KT1) and accept that this gives us some less precise location information.</p>
<pre><code>listings[<span>'zipcode'</span>] = listings[<span>'zipcode'</span>].str.slice(<span>0</span>,<span>3</span>)
listings[<span>'zipcode'</span>] = listings[<span>'zipcode'</span>].fillna(<span>&quot;OTHER&quot;</span>)
print(<span>&quot;Number of Zipcodes:&quot;</span>, listings[<span>'zipcode'</span>].nunique())</code></pre>
<pre><code>Number of Zipcodes: 461</code></pre>
<p>A lot of zipcodes contain less than 100 apartments and a few zipcodes contain most of the apartments. Let’s keep these ones.</p>
<pre><code>relevant_zipcodes = count_per_zipcode[count_per_zipcode > <span>100</span>].index
listings_zip_filtered = listings[listings[<span>'zipcode'</span>].isin(relevant_zipcodes)]

<span># Plot new zipcodes distribution</span>
count_per_zipcode = listings_zip_filtered[<span>'zipcode'</span>].value_counts()
ax = count_per_zipcode.plot(kind=<span>'bar'</span>, figsize = (<span>22</span>,<span>4</span>), color = <span>'#E35A5C'</span>, alpha = <span>0.85</span>)
ax.set_title(<span>&quot;Zipcodes by Number of Listings&quot;</span>)
ax.set_xlabel(<span>&quot;Zipcode&quot;</span>)
ax.set_ylabel(<span>&quot;# of Listings&quot;</span>)

plt.show()

print(<span>'Number of entries removed: '</span>, listings.shape[<span>0</span>] - listings_zip_filtered.shape[<span>0</span>])</code></pre>
<div><a rel="nofollow" href="https://i2.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_25_0.png?ssl=1" target="_blank"><img sizes="(max-width: 1291px) 100vw, 1291px" src="https://i2.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_25_0.png?w=450&ssl=1" alt="" class="wp-image-6273" data-recalc-dims="1"></a></div>
<pre><code>Number of entries removed:  5484</code></pre>
<p>This distribution is much better, and we only removed 5484 rows from our dataframe which contained about 53904 rows.</p>
</div>
<div>
<h4>Selection on Correlated Features</h4>
<p>Next we look at correlations.</p>
<pre><code><span>import</span> numpy <span>as</span> np
<span>from</span> sklearn <span>import</span> preprocessing

<span># Function to label encode categorical variables.</span>
<span># Input: array (array of values)</span>
<span># Output: array (array of encoded values)</span>
<span><span>def</span> <span>encode_categorical</span><span>(array)</span>:</span>
    <span>if</span> <span>not</span> array.dtype == np.dtype(<span>'float64'</span>):
        <span>return</span> preprocessing.LabelEncoder().fit_transform(array) 
    <span>else</span>:
        <span>return</span> array
    
<span># Temporary dataframe</span>
temp_data = listings_neighborhood_filtered.copy()

<span># Delete additional entries with NaN values</span>
temp_data = temp_data.dropna(axis=<span>0</span>)

<span># Encode categorical data</span>
temp_data = temp_data.apply(encode_categorical)
<span># Compute matrix of correlation coefficients</span>
corr_matrix = temp_data.corr()</code></pre>
<pre><code><span># Display heat map </span>
plt.figure(figsize=(<span>7</span>, <span>7</span>))
plt.pcolor(corr_matrix, cmap=<span>'RdBu'</span>)
plt.xlabel(<span>'Predictor Index'</span>)
plt.ylabel(<span>'Predictor Index'</span>)
plt.title(<span>'Heatmap of Correlation Matrix'</span>)
plt.colorbar()

plt.show()</code></pre>
<div><a rel="nofollow" href="https://i2.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_33_0.png?ssl=1" target="_blank"><img sizes="(max-width: 430px) 100vw, 430px" src="https://i2.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_33_0.png?resize=430%2C441&ssl=1" alt="" width="430" class="wp-image-6274" data-recalc-dims="1" height="441"></a></div>
<p>This reveals that <code>calculated_host_listings_count</code> is highly correlated with <code>host_total_listings_count</code> so we’ll keep the latter. We also see that the <code>availability_*</code> variables are correlated with each other. We’ll keep <code>availability_365</code> as this one is less correlated with other variables. Finally, we decide to drop <code>requires_license</code> which has an odd correlation result of NA’s which will not be useful in our model.</p>
<pre><code>useless = [<span>'calculated_host_listings_count'</span>, <span>'availability_30'</span>, <span>'availability_60'</span>, <span>'availability_90'</span>, <span>'requires_license'</span>]
listings_processed = listings_neighborhood_filtered.drop(useless, axis=<span>1</span>)</code></pre>
</div>

<div>
<h3>Data Splitting: Features / labels – Training set / testing set</h3>
<p>Now we split into features and labels and training and testing sets. We also convert the train and test dataframe into numpy arrays so that they can be used to train and test the models.</p>
<pre><code><span># Shuffle the data to ensure a good distribution for the training and testing sets</span>
<span>from</span> sklearn.utils <span>import</span> shuffle
listings_processed = shuffle(listings_processed)

<span># Extract features and labels</span>
y = listings_processed[<span>'price'</span>]
X = listings_processed.drop(<span>'price'</span>, axis = <span>1</span>)

<span># Training and Testing Sets</span>
<span>from</span> sklearn.model_selection <span>import</span> train_test_split
train_X, test_X, train_y, test_y = train_test_split(X, y, random_state = <span>0</span>)

train_X = np.array(train_X)
test_X = np.array(test_X)
train_y = np.array(train_y)
test_y = np.array(test_y)

train_X.shape, test_X.shape</code></pre>
<pre><code>((36185, 170), (12062, 170))</code></pre>
</div>
<div>
<h2>Modelling</h2>
<p>Now that the data preprocessing is over, we can start the second part of this work: applying different Machine Learning models. We decided to apply 3 different models:</p>
<ul>
<li>Random Forest, with the RandomForestRegressor from the Scikit-learn library</li>
<li>Gradient Boosting method, with the XGBRegressor from the XGBoost library</li>
<li>Neural Network, with the MLPRegressor from the Scikit-learn library.</li>
</ul>
<p>Each time, we applied the model with its default hyperparameters and we then tuned the model in order to get the best hyperparameters. The metrics we use to evaluate the models are the median absolute error due to the presence of extreme outliers and skewness in the data set.</p>
<p>We only show the code the Random Forest here, for the rest of the code please see the full version of this blogpost on our <a rel="nofollow" href="https://github.com/MangoTheCat/Modelling-Airbnb-Prices/tree/reproduce-results" target="_blank">GitHub</a>.</p>
<div>
<h3>Application of the Random Forest Regressor</h3>
<p>Let’s start with the Random Forest model.</p>
<div>
<h4>With default hyperparameters</h4>
<p>We first create a pipeline that imputes the missing values then scales the data and finally applies the model. We then fit this pipeline to the training set.</p>
<pre><code><span>from</span> sklearn.ensemble <span>import</span> RandomForestRegressor
<span>from</span> sklearn.pipeline <span>import</span> make_pipeline
<span>from</span> sklearn.preprocessing <span>import</span> Imputer
<span>from</span> sklearn.preprocessing <span>import</span> StandardScaler

<span># Create the pipeline (imputer + scaler + regressor)</span>
my_pipeline_RF = make_pipeline(Imputer(), StandardScaler(),
                               RandomForestRegressor(random_state=<span>42</span>))

<span># Fit the model</span>
my_pipeline_RF.fit(train_X, train_y)</code></pre>
<p>We evaluate this model on the test set, using the median absolute error to measure the performance of the model. We’ll also include the root-mean-square error (RMSE) for completeness. Since we’ll be doing this repeatedly it is good practice to create a function.</p>
<pre><code><span>from</span> sklearn.metrics <span>import</span> median_absolute_error
<span>from</span> sklearn.metrics <span>import</span> mean_squared_error
<span>from</span> math <span>import</span> sqrt

<span><span>def</span> <span>evaluate_model</span><span>(model, predict_set, evaluate_set)</span>:</span>
    predictions = model.predict(predict_set)
    print(<span>&quot;Median Absolute Error: &quot;</span> + str(round(median_absolute_error(predictions, evaluate_set), <span>2</span>))) 
    RMSE = round(sqrt(mean_squared_error(predictions, evaluate_set)), <span>2</span>)
    print(<span>&quot;RMSE: &quot;</span> + str(RMSE)) </code></pre>
<pre><code>evaluate_model(my_pipeline_RF, test_X, test_y)</code></pre>
<pre><code>Median Absolute Error: 14.2
RMSE: 126.16</code></pre>
</div>
<div>
<h4>Hyperparameters tuning</h4>
<p>We had some good results with the default hyperparameters of the Random Forest regressor. But we can improve the results with some hyperparameter tuning. There are two main methods available for this:</p>
<ul>
<li>Random search</li>
<li>Grid search</li>
</ul>
<p>You have to provide a parameter grid to these methods. Then, they both try different combinations of parameters within the grid you provided. But the first one only tries several combinations whereas the second one tries all the possible combinations with the grid you provided.</p>
<p>We started with a random search to roughly evaluate a good combination of parameters. Once this is complete, we use the grid search to get more precise results.</p>
<div>
<h5>Randomized Search with Cross Validation</h5>
<pre><code><span>import</span> numpy <span>as</span> np

<span># Number of trees in random forest</span>
n_estimators = [int(x) <span>for</span> x <span>in</span> np.linspace(start = <span>10</span>, stop = <span>1000</span>, num = <span>11</span>)]
<span># Number of features to consider at every split</span>
max_features = [<span>'auto'</span>, <span>'sqrt'</span>]
<span># Maximum number of levels in tree</span>
max_depth = [int(x) <span>for</span> x <span>in</span> np.linspace(<span>10</span>, <span>110</span>, num = <span>5</span>)]
max_depth.append(<span>None</span>)
<span># Minimum number of samples required to split a node</span>
min_samples_split = [<span>2</span>, <span>5</span>, <span>10</span>]
<span># Minimum number of samples required at each leaf node</span>
min_samples_leaf = [<span>1</span>, <span>2</span>, <span>4</span>]
<span># Method of selecting samples for training each tree</span>
bootstrap = [<span>True</span>, <span>False</span>]
<span># Create the random grid</span>
random_grid = {<span>'randomforestregressor__n_estimators'</span>: n_estimators,
               <span>'randomforestregressor__max_features'</span>: max_features,
               <span>'randomforestregressor__max_depth'</span>: max_depth,
               <span>'randomforestregressor__min_samples_split'</span>: min_samples_split,
               <span>'randomforestregressor__min_samples_leaf'</span>: min_samples_leaf,
               <span>'randomforestregressor__bootstrap'</span>: bootstrap}</code></pre>
<pre><code><span># Use the random grid to search for best hyperparameters</span>
<span>from</span> sklearn.model_selection <span>import</span> RandomizedSearchCV

<span># Random search of parameters, using 2 fold cross validation, </span>
<span># search across 100 different combinations, and use all available cores</span>
rf_random = RandomizedSearchCV(estimator = my_pipeline_RF, 
                               param_distributions = random_grid, 
                               n_iter = <span>50</span>, cv = <span>2</span>, verbose=<span>2</span>,
                               random_state = <span>42</span>, n_jobs = <span>-1</span>, 
                               scoring = <span>'neg_median_absolute_error'</span>)
<span># Fit our model</span>
rf_random.fit(train_X, train_y)

rf_random.best_params_</code></pre>
<pre><code>{'randomforestregressor__bootstrap': True,
 'randomforestregressor__max_depth': 35,
 'randomforestregressor__max_features': 'auto',
 'randomforestregressor__min_samples_leaf': 2,
 'randomforestregressor__min_samples_split': 5,
 'randomforestregressor__n_estimators': 1000}</code></pre>
</div>
<div>
<h5>Grid Search with Cross Validation</h5>
<pre><code><span>from</span> sklearn.model_selection <span>import</span> GridSearchCV
<span># Create the parameter grid based on the results of random search </span>
param_grid = {
    <span>'randomforestregressor__bootstrap'</span>: [<span>True</span>],
    <span>'randomforestregressor__max_depth'</span>: [<span>30</span>, <span>35</span>, <span>40</span>], 
    <span>'randomforestregressor__max_features'</span>: [<span>'auto'</span>],
    <span>'randomforestregressor__min_samples_leaf'</span>: [<span>2</span>],
    <span>'randomforestregressor__min_samples_split'</span>: [<span>4</span>, <span>5</span>, <span>6</span>],
    <span>'randomforestregressor__n_estimators'</span>: [<span>950</span>, <span>1000</span>, <span>1050</span>] 
}

<span># Instantiate the grid search model</span>
grid_search = GridSearchCV(estimator = my_pipeline_RF, 
                           param_grid = param_grid, 
                           cv = <span>3</span>, n_jobs = <span>-1</span>, verbose = <span>2</span>, 
                           scoring = <span>'neg_median_absolute_error'</span>)

<span># Fit the grid search to the data</span>
grid_search.fit(train_X, train_y)

grid_search.best_params_</code></pre>
<pre><code>{'randomforestregressor__bootstrap': True,
 'randomforestregressor__max_depth': 30,
 'randomforestregressor__max_features': 'auto',
 'randomforestregressor__min_samples_leaf': 2,
 'randomforestregressor__min_samples_split': 4,
 'randomforestregressor__n_estimators': 1050}</code></pre>
</div>
<div>
<h5>Final Model</h5>
<pre><code><span># Create the pipeline (imputer + scaler + regressor)</span>
my_pipeline_RF_grid = make_pipeline(Imputer(), StandardScaler(),
                                      RandomForestRegressor(random_state=<span>42</span>,
                                                            bootstrap = <span>True</span>,
                                                            max_depth = <span>30</span>,
                                                            max_features = <span>'auto'</span>,
                                                            min_samples_leaf = <span>2</span>,
                                                            min_samples_split = <span>4</span>,
                                                            n_estimators = <span>1050</span>))

<span># Fit the model</span>
my_pipeline_RF_grid.fit(train_X, train_y)

evaluate_model(my_pipeline_RF_grid, test_X, test_y)</code></pre>
<pre><code>Median Absolute Error: 13.57
RMSE: 125.04</code></pre>
<p>We get better results with the tuned model than with default hyperparameters, but the improvement of the median absolute error is not amazing. Maybe we will have better precision if we use another model.</p>
</div>
</div>
</div>
<div>
<h3>Visualisation of all models’ performance</h3>
<div><a rel="nofollow" href="https://i1.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_80_0.png?ssl=1" target="_blank"><img sizes="(max-width: 619px) 100vw, 619px" src="https://i1.wp.com/www.mango-solutions.com/wp-content/uploads/sites/6/2018/10/output_80_0.png?w=450&ssl=1" alt="" class="wp-image-6275" data-recalc-dims="1"></a></div>
<p>The tuned Random Forest and XGBoost gave the best results on the test set. Surprisingly, the Multi Layer Perceptron with default parameters gave the highest Median Absolute errors, and the tuned one did not even give better results than the default Random Forest. This is unusual, maybe the Multi Layer Perceptron needs more data to perform better, or it might need more tuning on important hyperparameters such as the hidden_layer_sizes.</p>
</div>
</div>
<div>
<h2>Conclusion</h2>
<p>In this post, we modelled Airbnb apartment prices using descriptive data from the Airbnb website. First, we preprocessed the data to remove any redundant features and reduce the sparsity of the data. Then we applied three different algorithms, initially with default parameters which we then tuned. In our results the tuned Random Forest and tuned XGBoost performed best.</p>
<p>To further improve our models we could include more feature engineering, for example, time-based features. We could also try more extensive hyperparameter tuning. If you would like to give it a go yourself, the code and data for this post can be found on <a rel="nofollow" href="https://github.com/MangoTheCat/Modelling-Airbnb-Prices#XGB" target="_blank">GitHub</a></p>
</div>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://www.mango-solutions.com/blog/modeling-airbnb-prices"> RBlog – Mango Solutions</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/p0ceSGobaIw" height="1"></a></div>