UNPKG

dataframe-js

Version:

Immutable and functional data structure for datascientists and developpers

211 lines (191 loc) 12.6 kB
<html> <head> <script src="../dist/dataframe-min.js"></script> </head> <body> <script> // In this example we will use dataframe-js to analyse a simple data set. // The aim of this snippet is (not really to explore data but) to play with the library in order to do simple things. // You will find the code, explanations and results as comments. // Here we import the lib. // You can also: import { DataFrame } from 'dataframe-js'; const DataFrame = dfjs.DataFrame; // Here we load the titanic data set from the well known Rdatasets (http://vincentarelbundock.github.io/Rdatasets/datasets.html). // We get the result via a Promise, as a new DataFrame. We rename it 'df'. DataFrame.fromCSV( "http://vincentarelbundock.github.io/Rdatasets/csv/COUNT/titanic.csv" ) .then(df => { // Let's go to display quicly our table. df.show(); // It looks like that, with one passenger by line. // | | class | age | sex | survived | // ------------------------------------------------------------ // | 1 | 1st class | adults | man | yes | // | 2 | 1st class | adults | man | yes | // | 3 | 1st class | adults | man | yes | // | 4 | 1st class | adults | man | yes | // | 5 | 1st class | adults | man | yes | // | 6 | 1st class | adults | man | yes | // | 7 | 1st class | adults | man | yes | // | 8 | 1st class | adults | man | yes | // | 9 | 1st class | adults | man | yes | // | 10 | 1st class | adults | man | yes | // Ok, in the csv, the first column was row index named as ''. We will rename this column. const cleanDF = df.rename("", "id"); // If we look at columnNames, the row index is replaced by the 'id' column name. console.log(cleanDF.listColumns()); // [ 'id', 'Class', 'Sex', 'Age', 'Survived', 'Freq' ] // Now, our DataFrame is 'clean' with. Let's go to a quick analysis. console.log("Total passengers:", cleanDF.count()); // We have 1316 passengers in the Titanic. console.log( "Survivors:", cleanDF.filter({ survived: "yes" }).count() ); // We have 499 survivors. console.log( "Died:", cleanDF .filter(row => row.get("survived") === "no") .count() ); // and 817 died passengers. // Ok now we will count the number of passengers by class + age + sex + survived by using groupBy and aggregation. const countByGroup = cleanDF .groupBy("class", "age", "sex", "survived") .aggregate(group => group.count()); // Ok, now we have the repartition of passengers by class + age + sex + survived. // But it could be easier to read if we rename the aggregation and sort rows by passengers. const cleanCountByGroup = countByGroup .rename("aggregation", "passengers") .sortBy("passengers", true); // And now show the result cleanCountByGroup.show(300); // | class | age | sex | survived | passengers | // ------------------------------------------------------------ // | 3rd class | adults | man | no | 387 | // | 2nd class | adults | man | no | 154 | // | 1st class | adults | women | yes | 140 | // | 1st class | adults | man | no | 118 | // | 3rd class | adults | women | no | 89 | // | 2nd class | adults | women | yes | 80 | // | 3rd class | adults | women | yes | 76 | // | 3rd class | adults | man | yes | 75 | // | 1st class | adults | man | yes | 57 | // | 3rd class | child | man | no | 35 | // OK, if we just look at this table, we can see that rich people (1s Class), and more specifically women have the largest number of survivors. // To resume this fact, it could be interesting to compute the % of survival for each group of passengers. // We can do this by this way: // First we compute the total number of passengers by class + age + sex. const passengersByGroup = cleanDF .groupBy("class", "age", "sex") .aggregate(group => group.count()) .rename("aggregation", "totalPassengers"); // Then we have to join with the cleanCountByGroup table. // And we compute a new Column, survival, to expose the percentage of survivors. // Then, we drop totalPassengers column which is now useless. const informationsByGroup = cleanCountByGroup .innerJoin(passengersByGroup, ["class", "age", "sex"]) .withColumn( "survival", row => row.get("passengers") / row.get("totalPassengers") ) .drop("totalPassengers"); informationsByGroup.show(100); // | class | age | sex | survived | passen... | survival | // ------------------------------------------------------------------------ // | 3rd class | adults | man | no | 387 | 0.8376... | // | 3rd class | adults | man | yes | 75 | 0.1623... | // | 3rd class | adults | women | no | 89 | 0.5393... | // | 3rd class | adults | women | yes | 76 | 0.4606... | // | 3rd class | child | man | no | 35 | 0.7291... | // | 3rd class | child | man | yes | 13 | 0.2708... | // | 3rd class | child | women | no | 17 | 0.5483... | // | 3rd class | child | women | yes | 14 | 0.4516... | // | 2nd class | adults | man | no | 154 | 0.9166... | // | 2nd class | adults | man | yes | 14 | 0.0833... | // | 2nd class | adults | women | yes | 80 | 0.8602... | // | 2nd class | adults | women | no | 13 | 0.1397... | // | 2nd class | child | man | yes | 11 | 1 | // | 2nd class | child | women | yes | 13 | 1 | // | 1st class | adults | man | no | 118 | 0.6742... | // | 1st class | adults | man | yes | 57 | 0.3257... | // | 1st class | adults | women | yes | 140 | 0.9722... | // | 1st class | adults | women | no | 4 | 0.0277... | // | 1st class | child | man | yes | 5 | 1 | // | 1st class | child | women | yes | 1 | 1 | // If we want to have an overview of the gender effects on survival we can use the DataFrame.stat module: informationsByGroup .groupBy("sex") .aggregate(group => group.stat.mean("survival")) .rename("aggregation", "mean") .show(); informationsByGroup .groupBy("sex") .aggregate(group => group.stat.sd("survival")) .rename("aggregation", "standard_deviation") .show(); // | sex | mean | // ------------------------ // | man | 0.6 | // | women | 0.6 | // | sex | standa... | // ------------------------ // | man | 0.3560... | // | women | 0.3517... | // Gender effects seem not obvious. What about the age effects on survival ? const survivalMeanByAge = informationsByGroup .groupBy("age") .aggregate(group => group.stat.mean("survival")) .rename("aggregation", "mean"); const survivalSDByAge = informationsByGroup .groupBy("age") .aggregate(group => group.stat.sd("survival")) .rename("aggregation", "standard_deviation"); survivalMeanByAge.show(); survivalSDByAge.show(); // | age | mean | // ------------------------ // | adults | 0.5 | // | child | 0.75 | // | age | standa... | // ------------------------ // | adults | 0.3496... | // | child | 0.2951... | // Ok that's better. // Now, our boss wants a csv export of the age effects, in an exotic format (excel, damn it): // | | adults | child | // ------------------------------------- // | mean | 0.5 | 0.75 | // | sd | 0.3496... | 0.2951... | // First we join our results. const ageEffect = survivalMeanByAge.innerJoin( survivalSDByAge, "age" ); ageEffect.show(); // We now remove age column (you will understand why in few lines) and transpose the table (with columnNames); const transposedAgeEffect = ageEffect .drop("age") .transpose(true); // It's magical, and it looks like that: transposedAgeEffect.show(); // Now we will use the previously removed age column as columnNames. // Then we reorganize columns order. const transposedAgeEffectWithColumnNames = transposedAgeEffect .renameAll([...ageEffect.toArray("age"), ""]) .restructure(["", "adults", "child"]); // you can also .select('', 'adults', 'child'); // Which gives the good table: transposedAgeEffectWithColumnNames.show(); // Now you have just to export it as a csv: transposedAgeEffectWithColumnNames.toCSV( true, "yourReport.csv" ); }) .catch(err => { console.log(err); }); </script> </body> </html>