<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Cloud AI Ecosystem Team Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/cloudai/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/cloudai/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:21:32 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>TensorFlow on Azure: Enabling Blob Storage via Alluxio</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudai/tensorflow-on-azure-enabling-blob-storage-via-alluxio</link>
      <pubDate>Tue, 01 May 2018 18:06:27 GMT</pubDate>
      <dc:creator><![CDATA[Jing Chang - MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cloudai/?p=45</guid>
      <description><![CDATA[Many customers Cloud AI Ecosystem in Microsoft works with, choose Azure Blob Storage as their data...]]></description>
      <content:encoded><![CDATA[Many customers Cloud AI Ecosystem in Microsoft works with, choose Azure Blob Storage as their data storage. Among those customers, if one wants to use TensorFlow to develop deep learning models, unfortunately TensorFlow does not support Azure Blob storage out of box as its custom file system plugin<sup><em>1</em></sup>.  There is no easy way to directly feed data from Azure block blobs into TensorFlow’s input pipeline<sup>2</sup>. In case of setting up a Kubernetes cluster for TensorFlow workloads, Azure Blob Storage is not included in k8s’ supported Types of Volumes<sup>3</sup>.

Given above, the odds are either to mount an Azure File share to Kubernetes pods and read remote Azure files via the mount path, or to manually copy data to a local SSD disk of each pod. Those approaches are summarized as part of ‘<em>Deep Learning Toolkits with Kubernetes Clusters’</em> published at <a href="https://aka.ms/deeplearningk8s">https://aka.ms/deeplearningk8s</a><u>; </u>however, many people would prefer Azure Blob to Azure File service because of their different performance, scale and pricing options<sup>5</sup>; or in the case of manual copy to local SSD, it’s not scalable to repeat that operation with big amount of training data.

In this blog we introduce Alluxio’s newly released FUSE<sup>6</sup> feature in Alluxio 1.7, which enables mounting Azure Blob storage to the local file system namespace, and solves integration between TensorFlow and Azure Blobs. It aims to bridge high computation workloads including TensorFlow jobs with underlying storage system, via its unified Alluxio data access layer.  Alluxio-FUSE feature opens up new opportunities for Azure Blobs to be directly fed into your tensors; moreover, with current progress made on GPU computation, the input pipeline might become a bottleneck if the storage is not performant enough. The effort Alluxio has paid to optimize data access layer brings positive impact to the DL data input pipeline. For more details, please refer to <a href="https://alluxio.com/blog/flexible-and-fast-storage-for-deep-learning-with-alluxio">https://alluxio.com/blog/flexible-and-fast-storage-for-deep-learning-with-alluxio</a>.

&nbsp;

Follow the simple steps below to check out how to enable Azure Blobs via Alluxio-FUSE to run TensorFlow jobs on Azure.
<h2>Set up A Kubernetes Cluster</h2>
A sample k8s cluster on Azure Container Service is deployed using open source toolkit DLWorkspace<sup><u>8</u></sup>, the documentation can be found at <a href="https://microsoft.github.io/DLWorkspace/">https://microsoft.github.io/DLWorkspace/</a><u>.  </u>The sample setup includes one master node of Standard D2 v2 Azure VM(2 vcpus, 7GB memory), and two agent nodes of Standard NC12(12 vcpus, 112 GB memory) Azure VM. To check if the GPU driver is correctly installed after deployment, run ‘<em>nvidia-smi’ </em>on each agent node to find the driver information.

&nbsp;
<h2>Create Alluxio-FUSE Enabled Pods</h2>
For ease of use, Alluxio includes Docker integration<sup>9</sup> and published its 1.7 Docker images<sup>10</sup> on Docker Hub, we can pull images into the k8s cluster and create Alluxio-FUSE enabled k8s pods. Alluxio servers consist of two architectural components<sup>11</sup>: master and workers, where the master is responsible for managing global metadata and workers are responsible for managing local storage resources allocated to Alluxio. We co-locate Alluxio master and TensorFlow parameter server on the same pod, also Alluxio workers and TensorFlow workers on the same pod, for better data locality.

Find sample pod configuration files posted at <a href="https://github.com/jichang1/TensorFlowonAzure/tree/master/Alluxio">https://github.com/jichang1/TensorFlowonAzure/tree/master/Alluxio</a> to create your k8s pods: first tf-ps pod and then tf-worker pod. Note you will replace <em>$yourcontainername$, $yourstorageaccountname$, and $yourstorageaccountkey$</em>. Replace <em>$yourpsserverip$</em> with the IP found from <em>/etc/hosts</em> of the tf-ps pod.

The sample container configuration below, tells that the docker image runs <em>/entrypoint.sh</em> upon initialization with argument “worker”; the worker pod communicates with the master pod using port 19998; a few environment variables need to be defined upon initialization such as master host name, storage account, etc; the process runs in privileged ‘SYS_ADMIN’ mode.
<pre><span>containers:</span>

<span>      - </span><span>name:</span><span> tf-worker0</span>

<span>        </span><span>image:</span><span> alluxio/alluxio-tensorflow:1.7.0-1.3.0-gpu</span>

<span>        </span><span>command:</span><span> </span><span>[</span><span>"/entrypoint.sh"</span><span>]</span>

<span>        </span><span>args:</span><span> </span><span>[</span><span>"worker"</span><span>]</span>

<span>        </span><span>ports:</span>

<span>          - </span><span>containerPort:</span><span> 19998</span>

<span>          </span><span>name:</span><span> alluxioport</span>

<span>        </span><span>env:</span>

<span>        - </span><span>name:</span><span> ALLUXIO_MASTER_HOSTNAME</span>

<span>          </span><span>value:</span><span> "$yourpsserverip$"</span>

<span>        - </span><span>name:</span><span> ALLUXIO_RAM_FOLDER</span>

<span>          </span><span>value:</span><span> "/opt/ramdisk"</span>

<span>        - </span><span>name:</span><span> ALLUXIO_WORKER_MEMORY_SIZE</span>

<span>          </span><span>value:</span><span> "10GB"</span>

<span>        - </span><span>name:</span><span> ALLUXIO_UNDERFS_ADDRESS</span>

<span>          </span><span>value:</span><span> "wasb://$yourcontainername$@$yourstorageaccountname$.blob.core.windows.net/"</span>

<span>        - </span><span>name:</span><span> FS_AZURE_ACCOUNT_KEY_$yourstorageaccountname$_BLOB_CORE_WINDOWS_NET</span>

<span>          </span><span>value:</span><span> $yourstorageaccountkey$</span>

<span>        </span><span>resources:</span>

<span>          </span><span>limits:</span>

<span>            </span><span>alpha.kubernetes.io/nvidia-gpu</span><span>: </span><span>1</span>

<span>        </span><span>volumeMounts:</span>

<span>        - </span><span>mountPath:</span><span> /usr/local/nvidia</span>

<span>          </span><span>name:</span><span> nvidia-driver</span>

<span>        - </span><span>mountPath:</span><span> /opt/ramdisk</span>

<span>          </span><span>name:</span><span> ramdisk</span>

<span>        - </span><span>mountPath:</span><span> /etc/resolv.conf</span>

<span>          </span><span>name:</span><span> resolv</span>

<span>        </span><span>securityContext:</span>

<span>          </span><span>privileged:</span><span> true</span>

<span>          </span><span>capabilities:</span>

<span>            </span><span>add:</span><span> </span><span>[</span><span>"SYS_ADMIN"</span><span>]</span>

<span><span style="color: #000000;font-family: Calibri">            </span></span><span>nodeSelector:</span>

<span>        </span><span>FragmentGPUJob:</span><span> active</span>

<span>      </span><span>volumes:</span>

<span>      - </span><span>name:</span><span> nvidia-driver</span>

<span>        </span><span>hostPath:</span>

<span>          </span><span>path:</span><span> /opt/nvidia-driver/current</span>

<span>      - </span><span>name:</span><span> ramdisk</span>

<span>        </span><span>hostPath:</span>

<span>          </span><span>path:</span><span> /mnt/ramdisk</span>

<span>      - </span><span>name:</span><span> resolv</span>

<span>        </span><span>hostPath:</span>

<span>          </span><span>path:</span><span> /etc/resolv.conf</span></pre>
&nbsp;

After executing
<pre><span style="color: #000000;font-family: Calibri">sudo kubectl apply -f ./alluxio-fuse-tfgpu-psserver0.yaml</span>

<span style="color: #000000;font-family: Calibri">sudo kubectl apply -f ./alluxio-fuse-tfgpu-worker0.yaml</span></pre>
Run
<pre><span style="color: #000000;font-family: Calibri">kubectl get pods</span></pre>
to check pods are up and in healthy state.

Connect to tf-ps or tf-worker pods, access your blob storage via ‘ls /<em>alluxio-fuse’</em> which is already mounted to local file system.

&nbsp;
<h2>Run TensorFlow Jobs</h2>
We take TensorFlow benchmark jobs<sup>12</sup> as an example.

On the parameter server pod, run the command below:
<pre><em>python tf_cnn_benchmarks.py --local_parameter_device=gpu --num_gpus=2  --batch_size=128  --model=googlenet  </em><em>--variable_update=parameter_server --num_batches=50  --cross_replica_sync=False  --data_name=imagenet --data_dir=file:///alluxio-fuse/  --job_name=ps --ps_hosts=10.244.2.2:2222  --worker_hosts=10.244.0.2:2222 --task_index=0</em></pre>
On the worker pod, run the command below:
<pre><em>python tf_cnn_benchmarks.py --local_parameter_device=gpu --num_gpus=2  --batch_size=128 --model=googlenet --variable_update=parameter_server --num_batches=50 --cross_replica_sync=False --data_name=imagenet --data_dir=file:///alluxio-fuse/  --job_name=worker  --ps_hosts=10.244.2.2:2222  --worker_hosts=10.244.0.2:2222 --task_index=0</em></pre>
You should observe output similar to below
<pre><span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">name: Tesla K80</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">major: 3 minor: 7 memoryClockRate (GHz) 0.8235</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">pciBusID 0e7c:00:00.0</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Total memory: 11.17GiB</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Free memory: 11.09GiB</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">……</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">2018-01-11 02:22:52.188017: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:0) -&gt; (device: 0, name: Tesla K80, pci bus id: 0e7c:00:00.0)</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">2018-01-11 02:22:52.188038: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:1) -&gt; (device: 1, name: Tesla K80, pci bus id: 27e6:00:00.0)</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">2018-01-11 02:22:52.402467: I tensorflow/core/distributed_runtime/rpc/grpc_channel.cc:215] Initialize GrpcChannelCache for job ps -&gt; {0 -&gt; 10.244.2.2:2222}</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">2018-01-11 02:22:52.402510: I tensorflow/core/distributed_runtime/rpc/grpc_channel.cc:215] Initialize GrpcChannelCache for job worker -&gt; {0 -&gt; localhost:2222}</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">2018-01-11 02:22:52.405246: I tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc:316] Started server with target: grpc://localhost:2222</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">TensorFlow:  1.3</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Model:       googlenet</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Mode:        training</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Batch size:  256 global</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">             128 per device</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Devices:     ['/job:worker/task:0/gpu:0', '/job:worker/task:0/gpu:1']</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Data format: NCHW</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Optimizer:   sgd</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Variables:   parameter_server</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Sync:        False</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">==========</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Generating model</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">2018-01-11 02:24:26.461062: I tensorflow/core/distributed_runtime/master_session.cc:998] Start master session b26ef5a1286e9840 with config: intra_op_parallelism_threads: 1 gpu_options { force_gpu_compatible: true } allow_soft_placement: true</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Running warm up</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Done warm up</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Waiting for other replicas to finish warm up</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Starting real work at step 10 at time Thu Jan 11 02:25:57 2018</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Step    Img/sec loss</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">1       images/sec: 200.3 +/- 0.0 (jitter = 0.0)        7.093</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">10      images/sec: 189.8 +/- 1.6 (jitter = 4.7)        7.093</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">20      images/sec: 186.3 +/- 1.3 (jitter = 6.3)        7.093</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">30      images/sec: 186.6 +/- 1.1 (jitter = 6.0)        7.093</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">40      images/sec: 186.8 +/- 0.9 (jitter = 5.5)        7.093</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">Finishing real work at step 59 at time Thu Jan 11 02:27:04 2018</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">50      images/sec: 187.4 +/- 0.8 (jitter = 5.3)        7.093</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">----------------------------------------------------------------</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">total images/sec: 186.67</span></span>

<span style="margin: 0px;font-family: 'Lucida Console';font-size: 8pt"><span style="color: #000000">----------------------------------------------------------------

</span></span></pre>
<span><span style="color: #000000;font-family: Calibri"> </span></span>We hope this blog has provided you a new way of running TensorFlow jobs on Azure with underlying Azure Blob storage.

<em> </em>

&nbsp;
<h2>Reference</h2>
1        <a href="https://www.tensorflow.org/extend/add_filesys">https://www.tensorflow.org/extend/add_filesys</a>

2        <a href="https://www.tensorflow.org/programmers_guide/datasets">https://www.tensorflow.org/programmers_guide/datasets</a>

3        <a href="https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes">https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes</a>

4        <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-scalability-targets">https://docs.microsoft.com/en-us/azure/storage/common/storage-scalability-targets</a>

5        <a href="https://azure.microsoft.com/en-us/pricing/details/storage/">https://azure.microsoft.com/en-us/pricing/details/storage/</a>

6        <a href="https://www.alluxio.org/docs/master/en/Mounting-Alluxio-FS-with-FUSE.html">https://www.alluxio.org/docs/master/en/Mounting-Alluxio-FS-with-FUSE.html</a>

7        <a href="https://www.alluxio.org/docs/master/en/index.html">https://www.alluxio.org/docs/master/en/index.html</a>

8        <a href="https://github.com/Microsoft/DLWorkspace">https://github.com/Microsoft/DLWorkspace</a>

9        <a href="https://github.com/Alluxio/alluxio/tree/master/integration/docker">https://github.com/Alluxio/alluxio/tree/master/integration/docker</a>

10    <a href="https://hub.docker.com/r/alluxio/alluxio-tensorflow/">https://hub.docker.com/r/alluxio/alluxio-tensorflow/</a>

11    <a href="https://www.alluxio.org/docs/master/en/Architecture.html">https://www.alluxio.org/docs/master/en/Architecture.html</a>

12    <a href="https://github.com/tensorflow/benchmarks">https://github.com/tensorflow/benchmarks</a>

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>How to Make Python Easier for the R User: revoscalepy</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudai/how-to-make-python-easier-for-the-r-user-revoscalepy</link>
      <pubDate>Mon, 20 Nov 2017 17:50:54 GMT</pubDate>
      <dc:creator><![CDATA[Siddarth Ramesh]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/cloudai/?p=35</guid>
      <description><![CDATA[Python for the R User 
I’m an R programmer. To me, R has been great for data exploration,...]]></description>
      <content:encoded><![CDATA[<div class="page" title="Page 1">
<div class="layoutArea">
<div class="column">
<h2><span>Python for the R User </span></h2>
<span>I’m an R programmer. To me, R has </span><span>been great for data exploration, transformation, statistical modeling, and visualizations. However, there is a huge community of Data Scientists and Analysts who turn to Python for these tasks. Moreover, both R and Python experts exist in most analytics organizations, and it is important for both languages to coexist. </span>

<span>Many times, this means that R coders will develop a workflow in R but then must redesign and recode it in Python for their production systems. If the coder is lucky, this is easy, and the R model can be exported as a serialized object and read into Python. There are packages that do this, such as </span><a href="https://cran.r-project.org/web/packages/pmml/index.html"><span>pmml</span></a><span>. Unfortunately, many times, this is more challenging because the production system </span><span>might demand that the entire end to end workflow is built exclusively in Python. That’s </span><span>sometimes tough because there are aspects of statistical model building in R which are more intuitive than Python. </span>

<span>Python has many strengths, such as its robust data structures (like Dictionaries), compatibility with Deep Learning and Spark, and its ability to be a multipurpose language. However, many scenarios in enterprise analytics require people to go back to basic statistics and Machine Learning, for which the classic Data Science packages in Python are not as intuitive as R. The key difference is that many statistical methods are built into R natively. As a result, there is a gap for when R users must build workflows in Python. To try to bridge this gap, this post will discuss a relatively new package developed by Microsoft, </span><span><a href="https://docs.microsoft.com/en-us/sql/advanced-analytics/python/what-is-revoscalepy">revoscalepy</a>. </span>
<h2><span>Why revoscalepy? </span></h2>
<span>Revoscalepy is the Python implementation of the R library </span><a href="https://docs.microsoft.com/en-us/machine-learning-server/r-reference/revoscaler/revoscaler"><span>RevoScaleR</span></a><span>. </span>

<span>The methods in ‘revoscalepy’ are the same, and more importantly, the way </span><span>the R user can </span><span>view </span><span>data is the same. The reason this is so important is that for an R programmer, being able to understand the data shape and structure is one of the challenges with getting used to Python. </span>

</div>
</div>
</div>
<div class="page" title="Page 2">
<div class="layoutArea">
<div class="column">

<em>In Python, data types are different, preprocessing the data is different, and the criteria to feed the processed dataset into a model is different. </em>

<span>To understand how revoscalepy eases the transition from R to Python, the following section will compare building a decision tree using revoscalepy with building a decision tree using sklearn. The </span><a href="https://www.kaggle.com/c/titanic"><span>Titanic </span></a><span>dataset from Kaggle will be used for this example. To be clear, this post is written </span><span>from an R user’s perspective, as many of the challenges this post will outline are standard </span><span>practices for native Python users. </span>
<h2><span>Revoscalepy Versus Sklearn </span></h2>
<h3><span>Dependencies of revoscalepy </span></h3>
<span>Revoscalepy works on Python 3.5, and can be downloaded as a part of </span><a href="https://docs.microsoft.com/en-us/machine-learning-server/what-is-machine-learning-server"><span>Microsoft Machine Learning Server</span></a><span>. Once downloaded, set the Python environment path to the python executable in the MML directory, and then import the packages. </span>
<h3><span>Data Import </span></h3>
<span>The first chunk of code imports the revoscalepy, numpy, pandas, and sklearn packages. Pandas has some R roots in that it has its own implementation of DataFrames as well as methods that resemble </span><span>R’s exploratory methods. </span>
<pre><span>import </span><span>revoscalepy </span><span>as </span><span>rp</span><span>
</span><span>import </span><span>numpy </span><span>as </span><span>np</span><span>
</span><span>import </span><span>pandas </span><span>as </span><span>pd</span><span>
</span><span>import </span><span>sklearn </span><span>as </span><span>sk</span><span>
</span><span>titanic_data = </span><span>pd</span><span>.read_csv(</span><span>'titanic.csv'</span><span>)
titanic_data.head()
</span></pre>
<h3><span>Preprocessing </span></h3>
<em><strong>sklearn</strong> </em>

<span>One of the challenges as an R user with using sklearn is that the decision tree model for sklearn can only handle the numeric datatype. </span><span>Pandas has a categorical type that looks like factors in R, but sklearn</span><span>’s </span><span>decision tree does not integrate with this. </span><span>As a result, numerically encoding the categorical data becomes a mandatory step. This example will use a one-hot encoder to shape </span><span>the categories in a way that sklearn’s decision tree understands</span><span>. </span>

<span>The side effect of having to one-hot encode variables is that if the dataset contains high cardinality features, it can be memory intensive and computationally expensive because each </span>category becomes its own binary column. While implementing one-hot encoding itself is not a difficult transformation in Python and provides good results, it is still an extra step for an R programmer to have to manually implement. The following chunk of code detaches the categorical columns, label and one-hot encodes them, and then reattaches the encoded columns to the rest of the dataset.

</div>
</div>
</div>
<div class="page" title="Page 3">
<div class="layoutArea">
<div class="column">
<pre><span>from </span><span>sklearn </span><span>import </span><span>tree
</span><span>le = </span><span>sk</span><span>.</span><span>preprocessing</span><span>.</span><span>LabelEncoder</span><span>()
x = titanic_data.select_dtypes(include=[</span><span>object</span><span>])
x = x.drop([</span><span>'Name'</span><span>, </span><span>'Ticket'</span><span>, </span><span>'Cabin'</span><span>], 1)
x = </span><span>pd</span><span>.concat([x, titanic_data[</span><span>'Pclass'</span><span>]], axis = 1)
x[</span><span>'Pclass'</span><span>] = x[</span><span>'Pclass'</span><span>].astype(</span><span>'object'</span><span>)
x = </span><span>pd</span><span>.</span><span>DataFrame</span><span>(x)
x = x.fillna(</span><span>'Missing'</span><span>)
x_cats = x.apply(le.fit_transform)
enc = </span><span>sk</span><span>.</span><span>preprocessing</span><span>.</span><span>OneHotEncoder</span><span>()
enc.fit(x_cats)
onehotlabels = enc.transform(x_cats).toarray()
encoded_titanic_data =
</span><span>     pd</span><span>.concat([</span><span>pd</span><span>.</span><span>DataFrame</span><span>(titanic_data.select_dtypes(include=[</span><span>np</span><span>.number])),
</span><span>     pd</span><span>.</span><span>DataFrame</span><span>(onehotlabels)], axis = 1)
</span></pre>
<span>At this point, there are more columns than before, and the columns no longer have semantic names (they have been enumerated). This means that if a decision tree is visualized, it will be difficult to understand without going through the extra step of renaming these columns. There are techniques in Python to help with this, but it is still an extra step that must be considered. </span>

<em><strong>revoscalepy </strong></em>

<span>Unlike sklearn, revoscalepy reads </span><span>pandas’ ‘category’ type like factors </span><span>in R. This section of code </span><span>iterates through the DataFrame, finds the string types, and converts those types to ‘category’. </span><span>In pandas, there is an argument to set the order to False, to prevent ordered factors. </span>
<pre><span>titanic_data_object_types = titanic_data.select_dtypes(include = [</span><span>'object'</span><span>])
titanic_data_object_types_columns = </span><span>np</span><span>.array(titanic_data_object_types.columns)
</span><span>for </span><span>column </span><span>in </span><span>titanic_data_object_types_columns:
</span><span>     titanic_data[column] = titanic_data[column].astype(</span><span>'category'</span><span>, ordered = </span><span>False</span><span>)
titanic_data[</span><span>'Pclass'</span><span>] = titanic_data[</span><span>'Pclass'</span><span>].astype(</span><span>'category'</span><span>, ordered = </span><span>False</span><span>)
</span></pre>
<span>This dataset is already ready to be fed into the revoscalepy model. </span>
<h3><span>Training Models </span></h3>
<em><strong>sklearn </strong></em>

<span>One difference between implementing a model in R and in sklearn in Python is that sklearn does not use formulas. </span>

<span>Formulas are important and useful for modeling because they provide a consistent framework to develop models with varying degrees of complexity. With formulas, users can easily apply </span>different types of variable cases, such as ‘+’ for separate independent variables, ‘:’ for interaction terms, and ‘*’ to include both the variable and its interaction terms, along with <a href="https://faculty.chicagobooth.edu/richard.hahn/teaching/formulanotation.pdf">many other convenient calculations</a>. Within a formula, users can implement mathematical calculations, create factors, and include more complex entities like third order interactions. In addition, with formulas, programmers can build extraordinarily complex models such as mixed effect models, which are next to impossible build without them. In Python, there are packages such as ‘statsmodels’ which have more intuitive ways to build certain statistical models. However, statsmodels has a limited selection of models, and does not include tree based models.

</div>
</div>
</div>
<div class="page" title="Page 4">
<div class="layoutArea">
<div class="column">

<span>With sklearn, model.fit expects the independent and dependent terms to be columns from the DataFrame. Interactions must be created manually as a preprocessing step for more complex examples. The code below trains the decision tree: </span>
<pre><span>model = </span><span>tree</span><span>.</span><span>DecisionTreeClassifier</span><span>(max_depth = 50)
x = encoded_titanic_data.drop([</span><span>'Survived'</span><span>], 1)
x = x.fillna(-1)
y =  encoded_titanic_data[</span><span>'Survived'</span><span>]
</span><span>model = model.fit(x,y)
</span></pre>
<em><strong>revoscalepy</strong> </em>

<span>Revoscalepy brings back formulas. Granted, users cannot view the formula the same way as they can in R, because formulas are strings in Python. However, importing code from R to Python is an easy transition because formulas are read the same way in the revoscalepy functions as the model-fit functions in R. The code below fits the decision tree in revoscalepy: </span>
<pre><span>form = </span><span>'Survived ~ Pclass + Sex + Age  + Parch  + Fare + Embarked'
</span><span>titanic_data_tree = </span><span>rp</span><span>.</span><span>rx_dtree</span><span>(form, titanic_data, max_depth = 50)
</span></pre>
<span>The resulting object, </span><span>titanic_data_tree</span><span>, is the same structural object that RxDTree() would create in R. RxDTree() integrates with the rpart library in R, meaning rx_dtree() indirectly also has this integration if the users wants to export the object back into R for further exploratory analysis around this decision tree. </span>
<h2><span>Conclusion </span></h2>
<span>From the workflow, it should be clear how revoscalepy can help with transliteration between R and Python. Sklearn has different preprocessing considerations because the data must be fed into the model differently. The advantage to revoscalepy is that R programmers can easily convert their R co</span><span>de to Python without thinking too much about the ‘Pythonic way’ of </span>implementing their R code. Categories replace factors, rx_dtree() reads the R-like formula, and the arguments of the function are similar to their R equivalent. Looking at the big picture, revoscalepy is one way to ease Python for the R user and future posts will cover more ways to transition between R and Python.

</div>
</div>
</div>]]></content:encoded>
    </item>
  </channel>
</rss>