Showing posts with label data frame. Show all posts
Showing posts with label data frame. Show all posts

August 21, 2014

Basic Data Type in Data Processing Programing Language

Programming languages focus on various basic data types, subject to their different design goals. Languages such as Java and C# are designed to develop the common applications. Their basic data types are character strings, number, boolean, and other atomic data type, array and common object. SQL, PowerBuilder, R, esProc, and other alike languages are designed to process data. So their basic data types are the structured 2-dimentional data sheet object. Take this SQL statement, for example,SELECT T1.id,T1.name,T1.value FROM T1 LEFT JOIN T2 ON T1.id=T2.id. Of which, the T1, T2, and the computed result just use such data type. With the multiple fields to form one record and the multiple records to form the 2-dimentional data, the combination of such data and its field name is the structured 2-dimenional data table object.

Why not use the atomic data type and the common object as the basic data type for the data processing languages? If representing the T1 and T2 from the above-mentioned SQL statement with the array or Array List object, you will find: The complexity will increase for several times, and the length of codes will also increase sharply for dozens of times.

The basic data types of data processing languages are the structured 2-dimensional data table object. This is not a coincidence, but there are subtle reasons instead.

Correspond to actual business. In the real world, most business data is the structured data. As an example, the Payroll list has the employee number, employee name, department, date, pre-tax salary, and post-tax salary; For another example, the retail record has the order time, outlet number, checkout counter number, cashier number, product name, and unit price; The last example of business data is the Website log, which comprises the browse time, URL, visitor IP, browser version, and other properties. These properties are equivalent to the field. Each of the records has the same structure. Though they are stored in text while not the database, they are actually still the structured data in nature. So, it is only natural to use the 2-dimensional data table to represent it. The structured 2-dimensional data table object can be used to represent the business data intuitively. Representing the actual business in the most faithful way, no matter the storage, computing, exchange or sharing. Such kind of data is the easiest for users to understand in a most convenient way.

Easy for massive processing. Business data are mostly the data of the same structure, for example, the Payroll table, Retail record, and Website log mentioned above. In processing such data, in some cases, we will handle a certain data of a certain record, but in most cases, we take a certain record as unit to process all data, for example: Compute the after-tax wage based on the pre-tax wage; Compute the amount based on the unit price and quantity of commodity. Count the daily on-line duration for each IP. The above-mentioned processing mode is just the massive data processing. To implement the batch processing, we can traverse every member of array in loops by row number and column number just as the operations for Java. Alternatively, we can operation on the data with the business field name directly as we would do for SQL and esProc. The latter resolution is simpler and easier-to-use without having to write loop statements. Programmers can thus operate on data intuitively from business perceptive, and the corresponding code become more concise and readable.

Compatible with the Relational Algebra. The relational algebra is the underlying theory developed for data processing and query. By which, the association and laws of operations among business data can be expressed in full details using the basic operation along with the join operation, aggregation operation, and division operation. Theoretically, any computation problem of any degree of difficulty can be implemented and solved by relational algebra in the respects of data processing and data query. Because the relational algebra is concise and complete, databases are largely designed based on this theory. E.F. Codd is thus called as the father of relational database. The structured 2-dimensional data table object is just the data type recommended by E.F. Codd. This data type can be used to express various operations of relational algebra, so as to solve the computation problem in data processing easily. In facts, the database result set is the earliest structured 2-dimensional data table object.
As can be seen, all kinds of programming languages adopt the structured 2-dimental data table object as the basic data type because it is corresponding to the real business data, and easy to implement the massive computation, making it compatible to the relational algebra theory. With the 2-dimensional data table object, codes can be simple and easy to understand, and the development efficiency is improved. Let me explain it with a few more examples below:

Result set of SQL (resultSet): Group by the book type to compute the average price of the books whose average price is greater than 15 yuan.
    select avg(price),type from books group by type having avg(price)>15

Table sequence of esProc (TSeq): Group by department to find the top 10 best sellers for each department.
    products. group(department). (~.top(quantity;10)

Data window of PowerBuilder (datawindow): Sort the order by price
    Order.SetSort('value d')
    Order.Sort()

R language data frame (data.frame): Left-join the orders table and customer table by customerID.
    merge(A1,B1,by.x="CustomerID",by.y="CustomerID",all.x=TRUE)

SQL, esProc, and R code comparison: Group the order data by department, and summarize the order data and sales amount of each department.
SQL:
    Select count(*),sum(sales) from orders group by Dept

esProc:
    orders.groups(Dept; count(~), sum(sales))

R language:
 result<-aggregate(orders$ sales,list(orders $ Dept),sum) 
 result$count<-tapply(orders $ sales, orders $ Dept,length)
        
Let's take a close look on result set, table sequence, data window, and data frame. Although they are all structured 2-dimensional data table objects with basically the same function. There are some slight differences between them.
SQL result set is rich in various materials, widely applied, universal, and simple to use. It is the top mainstream data type of all data processing languages. However, SQL did not implement the relational algebra to the full, making it a bit inconvenient for some computations, such as the set division.

DataWindow usually retrieves number from SQL, and return the final result to the database. It mainly servers the purpose of breaking through any barrier between the data and UI controls, so that programmers can design and deliver the database application with high interactivity soon. Another major function of DataWindow is to render and edit data. It can be only used for form computation, and the data processing capability is relatively poor.

Data Frame is capable of handling the structured computation to some extent. As can be seen from the above example, its syntax is obscure, and it is relatively complex to implement the same functions with it. This is because the major functions of R are scientific and statistical computing, focusing on the data types of array and matrix. As a additional data type, the data frame was later introduced to implement the structured data computing. Considering this point, data frame is not so dedicated as that of the other three tools.

TSeq is quite dedicated in data processing. Having incorporated all common strong points of SQL result sets, TSeq can fully and completely implement the relational algebra. TSeq is generic and sorted, especially fit for the order-related complex computing in data processing, for example: Yearly link relative ratio, year-on-year comparison, ranking, relative position computing, and interval computing. TSeq is also charactered for it is generic, and easier to establish relations between data and provide access to data with multi-level association easily by object. Compared with SQL, TSeq is unable to directly process the big data because it is the pure memory object.

As can be seen, the structured 2-dimensional data table object is directly related to the degree of dedication for the data processing languages. The more powerful the former one is, the higher the degree of dedication for the latter one would be, and vice versa. If a programming language lack the structured 2-dimensional data table object, then this language can hardly be regarded as a dedicated one in processing the data. To research and examine if a programming language can be used to develop any application for data analysis and processing efficiently, the key is to find out if it offers the dedicated 2-dimensional data table object and the appropriate class library.

Perl is often used to retrieve character string and is capable of processing the data to some extent. However, since its code is lengthy and complex, it is not the dedicated data processing language. For example, to complete the simplest algorithm of grouping and summarizing, the code of Perl is shown below:
    %groups=();                       
    for each(@carts){             
        $name = $_->[1];
        if($groups{$name} == null){    
            $groups{$name}=[$_];
        }
        else{
            push($groups{$name},$_);     
             }
    }
    my @result=();                           
    for each( keys(%groups)){        
             $value=0;
        while($row=pop $groups{$_}){        
             $value += $row->[2];                
        }
        push @result,[$_,$value];
    }

Python is a bit simpler to write, but far more inefficient than SQL, esProc, and R in developing by order of magnitude. The sample code is shown below:
    result=[]
    for key, items in groupby(data, itemgetter(0)):      
        value1=0
        value2=0
        for subitem in items:                                            
            value1+=subitem[1]
            value2+=subitem[2]
        result.append([key,value1,value2])                  
    print(result)

Perl and Python is not the dedicated tools on data processing. Most importantly, they lack the structured 2-dimensional table data object.

The TSeq of esProc is not only the structured 2-dimensional table data object, but also is characterized with its being order, generic, step-by-step computation, making it more dedicated than other alike languages. For example, to implement a relatively complex computational goal: Find the shares having been rising on 5 consecutive days. esProc solution code is shown below:

July 16, 2014

Comparison Between esProc’s Sequence Table Object and R’s Data Frame (II)

Comparison Between esProc’s Sequence Table Object and R’s Data Frame (I)

Actual case

In this part we use a real case for comprehensive comparison o fdata frame and sequence table.
Computation target: according to daily transactions, selecting stocks from blue-chip stocks whose prices rises in 5 days in a row.

Ideas: Importing data; filtering out previous month's data; grouped them according to the ticker; sort the data by dates; compute the growth amount for closing price over previous day; compute the number of days for continuous positive growth; filtering out the stocks which rise in 5 or more days in a row.

Sequence Table Solution:


Data frame Solution:

01     library(gdata) #use excel function library
02     A1<- read.xls("e:\\data\\all.xlsx") #import data
03     A2<-subset(A1,as.POSIXlt(Date)>=as.POSIXlt('2012-06-01') &as.POSIXlt(Date)<=as.POSIXlt('2012-06-30')) #filter by date
04     A3 <- split(A2,A2$Code) #group by Code
05     A8<-list()
06     for(i in 1:length(A3)){
07       A3[[i]][order(as.numeric(A3[[i]]$Date)),] #sort by Date in each group
08       A3[[i]]$INC<-with(A3[[i]], Close-c(0,Close[- length (Close)])) #add a column, increased price
09       if(nrow(A3[[i]])>0){  #add a column, continuous increased days
10         A3[[i]]$CID[[1]]<-1
11         for(j in 2:nrow(A3[[i]])){
12           if(A3[[i]]$INC[[j]]>0 ){
13             A3[[i]]$CID[[j]]<-A3[[i]]$CID[[j-1]]+1
14           }else{
15             A3[[i]]$CID[[j]]<-0
16           }
17         }   
18       }
19       if(max(A3[[i]]$CID)>=5){  #stock max CID is bigger than 5
20         A8[[length(A8)+1]]<-A3[[i]]
21       }
22     }
23     A9<-lapply(A8,function(x) x$Code[[1]]) #finally,stock code

Comparison:
1. Data frame function is not rich enough, and is lack of professionalism. We need to use nested loops to meet the requirement in this case. It’s of low computational efficiency. Sequence table has rich and diverse functions. Without the use of loop statement we can achieve the same purpose. The code is shorter and simpler, and the performance is higher.

2. When programming for data frame, the code is obscure and hard to write. With sequence table, the code is clear and easy to understand. The cost of learning is lower.

3. When large amount of data is involved in this scenario, the memory consumption will be huge. Sequence table is computationby reference, which consumes less memory. Data frame is computation by value pass. The memory consumption is several times more than sequence table. It easy to result into memory overflow in this scenario.

4.To import Excel data into data frame, R requires third-party software packages. However they seem to have difficulty working together. Data import needs ten minutes to complete. With sequence table this only needs tens of seconds.

Test Performance

Test 1: Generating 10 million records in memory, each consists of three fields. All values ​​are random numbers. Records are filtered, and each field is summed.
         
Sequence table:


Data frame:

> library(timeDate)
> start=Sys.timeDate()
> col1=rnorm(n=10000000,mean=20000,sd=10000)
> col2=rnorm(n=10000000,mean=40000,sd=10000)
> col3=rnorm(n=10000000,mean=80000,sd=10000)
> data1=data.frame(col1,col2,col3)
> data2=subset(data1,col1>90)
> result=colSums(data2)
> print(result)
        col1         col2         col3
200844165732 390691612886 781453730448
> end=Sys.timeDate()
> print(end-start)
Time difference of 1.533333 mins

Comparison: sequence table needs 50.534 seconds, while data frame needs 91.999 seconds. The gap is obvious.

Test 2: Retrieving 1.2G txt file. Do filtering and sum on two fields

Sequence Table:


Data frame:

>library(timeDate)
> start=Sys.timeDate()
> data<-read.table("d:/T21.txt",sep = "\t")
> data1=subset(data,V1>90,select=c(V9,V11))
> result=colSums(data1)
> print(result)
         V9         V11
 5942982895          59484930179
> end=Sys.timeDate()
> print(end-start)
Time difference of 1.134722 hours

Comparison: sequence table takes 87.122 seconds, while data frame takes 1.1347 hours. The performance difference is tens of times. The reason for this is mainly due to the extremely low speed for file reading.

From the above comparison, we can see that sequence table are better than data frame in terms of rich features, easy syntax, memory consumption, development effort, library function performance and coding performance, etc.. Of course, data frame is not the full strength of R language. R has a powerful vector matrix and the associated mass functions, which make it more professional than esProc in scientific and engineering computation. 

Comparison Between esProc’s Sequence Table Object and R’s Data Frame (I)

Both esProc and R language are typical data processing and analysis languages with two-dimensional structured data objects. They are all good at multi-step complex computations. However their two-dimensional structured data objects are quite different from each other in the underlying mechanism. As a result, esProc is better at computation with structured data, and especially suitable for developers to do business computing. R is better at matrix computation and more suitable for scientists to do scientific or engineering computation.

esProc's two-dimensional structured data type is sequence table object (TSeq). Sequence table is based on records, with multiple records forming a row-styled two-dimensional table. In combination with the column name, this two-dimensional table can form a complete data structure. R language is based on vector, with multiple vectors forming a column-styled two-dimensional table. In combination with the column name, the two-dimensional table can form a complete data structure.
These underlying mechanisms affect actual user experience. In the following part we will compare the difference in practical use between sequence table object and data frame, in terms of basic functions, advanced features, actual use cases and test results.
Note: Primitive functions of development language are to be used in the following comparisons, the third party extension packages won’t be involved.

Basic functions

Example 1:retrieve two-dimensional structured data from the file, and access the value of the second column in the first row by coordinates.

Data frame:
         data<-read.table("e:/sales.txt",header=TRUE,sep="\t")
         result<-data[1,2]         

Sequence table:
         =data=file("e:/sales.txt").import@t()
         =data(1).#2

Comparison: there is no significant difference in the most basic functions.
Note: the sales.txt file is tab separated structured data, and the first few lines are as following:
OrderID   Client        SellerId     Amount    OrderDate
1          WVF             5         440.00      2009-2-3 0:00:00
2          UFS             13        1863.40     2009-7-5 0:00:00
3          SWFR            2         1813.00     2009-7-8 0:00:00
4          JFS             27        670.80      2009-7-8 0:00:00
5          DSG             15        3730.00     2009-7-9 0:00:00

Example 2: access the value of the second column in the first row, by row number and by field name.

Data frame:
         Result1<-data$Client[1]
         Result2<-data[1,]$Client

Sequence table:
         =data(1).(Client)
         =data.(Client)(1)
Comparison: there is no significant difference between the two.

Example 3: Access column data. There are two scenarios, and each falls into two situations: access by column number and column names:retrieve only the second column, or retrieve a combination of the second column and the fourth column.

Data frame:
         Result1<-data[2]
         Result2<-data[,c(2,4)]
         Result3<-data$Client
         Result4<-data[,c("Client","Amount")]

Sequence table:
         =data.(#2)
         =data.new(#2,#4)
         =data.(Client)
         =data.new(Client,Amount)
Comparison: Both can access the column data. The only difference is in the syntax for retrieving multiple column data. Data frame is retrieving the number directly, while with sequence table a new sequence table will be build with the new function. Although the syntax is different, the actual methods used are the same: both are duplicating two columns of data from the original objects to new objects.

Example 4: record manipulation. Includes: retrieve the first two records, appending records, inserting record in the second row, deleting the record in the second row.

Data frame:
         Record1<-data[c(1,2),]

         append<- data.frame(OrderID=152,  Client="CA",       SellerId=5,        Amount=2961.40,   OrderDate="2010-12-5 0:00:00")
         data<- rbind(data, append)
         insert<-data.frame(OrderID=153,  Client="RA",  SellerId=4,     Amount=1931.20,   OrderDate="2009-11-5 0:00:00")
         data<-rbind(data[1,], insert,data[2:151,]) 
         data<-data[-2,]

Sequence table:
         =data([1,2])
         =data.insert(0,152:OrderID,"CA":Client,5:SellerId,2961.40:Amount,"2010-12-5 0:00:00":OrderDate)
         =data.insert(2,153:OrderID,"RA":Client,4:SellerId,1931.20:Amount,"2009-11-5 0:00:00":OrderDate)
         =data.delete(2)

Comparison: record manipulation is possible in both ways. esProc is relatively more convenient. It can use insert function to append or insert records directly to sequence table, while in R language we need to split the data frame and then merge them again to achieve the same result in an indirect way.

Summary:
As both sequence table and data frame are structured, two-dimensional data object, no significant difference exists in basic functions for data reading/writing,data access and maintenance.

Advanced features

Example 5: modifying the association. A1, A2 are two-dimensional structured data object with the same field ID. We now need to add the bonus field values of A2 to the salary field values ​​in A1 according to ID.

Sequence table:
         A1=db.query("select id,name,salary from salary order by id")
         A2=db.query("select id,bonus from bonus order by id")
         A1.modify(1:A2,salary+bonus:salary)              
Data frame has no functions to modify the association. We need to do manual coding for this, which is omitted here.

Example 6: merging associations. A1, A2, A3 are two-dimensional structured data objects with the same field sequence number. Please associate them with left join. As the data is sorted by sequence number, please leverage merging methods to improve the speed for association.

Sequence Table:join@m1(A1:salary,id;     A2:bonus,id;   A3,attendance,id)
Data frame supports association of two tables, such as: merge(A1,A2,by.x="id",by.y="id",all=TRUE).
In this case three tables are associated, which can be achieved indirectly through two two-table associations.

In addition, the data frame does not support merging of association, and therefore no speed improvement is possible. In other words, data frame cannot use ordered sequence data to improve performance, not only with association, but also with other operations.

Example 7: Record lookup. Four scenarios: retrieving records with the Amount greater than 1000; retrieving the sequence number or records with the Amount greater than 1000;return records with primary key value of “v”, return the sequence number for records with primary key value of “v”.

Sequence table:
    =data.select(Amount>1000)  
    = data.pselect(Amount>1000)        
    = data.find(v)           
    = data.pfind(v)         

Data frame:only the first two scenarios can be achieved, which is done with following code:
    newdata<- data [data $ Amount>1000,]        
    which(data $ Amount >1000) 

Data frame hasn't the concept of major key, so we need to do manual coding for other 2 scenarios as indirect methods, or employ a third party package (i.e. data.table). The codes are omitted here.

Example 8: Group sum. The data is grouped by Client and SellerId. Then the other two fields are aggregated: do a sum for Amount field, and do a count for OrderID field.

Sequence table:
         =data.groups(Client,SellerId;sum(Amount),count(OrderID))

Data frame:only support single field aggregation, such as the sum of Amount. As following:
         result<aggregate(data[,4],data[c(2,3)],sum)

To do aggregation of two fields at the same time with data frame, we can only use two separate aggregate statements and then merge the results. Codes are omitted here.

Example 9: Reuse grouping. Group data by Client. Complete multiple subsequent computations on group result. Including: aggregation by amount, and count after grouping by SellerId.

Sequence table:
         A2=data.group(Client)
         =A2.(~.sum(Amount))
         =A2.(~.groups(SellerId;count(OrderID)))

Data frame does not support reuse of grouping directly. Grouping and aggregation usually need to be done in one step. This means we need to do two identical grouping operations to accomplish the same purpose. As following:
         result<-aggregate(data[,2],sum)
         result<-aggregate(data[,2],data[,3],count)

If we want to reuse grouping, we must use split function and loop to achieve this. The code is both lengthy and with low performance.

Summary:
Sequence tables and data frame are quite different in terms of advanced features. This is mainly demonstrated in the following five ways:

1. Richness of features. Sequence table has rich functions, and is very convenient to do structured data computation. Data frame originates from matrix, with less support for structured data and lack of many features. Use of the third party packages can in some degree supplement the functions data frame lacks, but these packages are no match for R’s primitive library function in muturity and stability.
2. Difficulty in syntax. The function names of sequence table are more intuitive.For example, select means to find; pselect is to find the location (position). With data frame the syntax is relatively obscure. For example, “find by field” is data [data $ Amount> 1000,], and retrieve value by field is data[,"Amount"]. These two are confusing and difficult for the programmer to understand. One must have some knowledge on vector to grasp it.
3. Memory consumption. Basically sequence table function only returns a reference, with very little memory occupation. Data frame must copied record from the original object. If we need to do multiple search, association and grouping operations on large amounts of data, data frame’s memory consumption will be very large. It will impact the whole system.
4. Code workload and code performance. The functions supported by data frame are not rich enough. We need to do hand-coding to achieve this indirectly. This means more workload. The R interpreter is known to be very slow. With hand-coding the performance is much lower than library functions.

5. Library function performance. Sequence table has many functions to improve computing performance, such as merging association, grouping functions, binary search, hash lookup. Although data frame supports association, aggregation and search, it’s hard to improve the performance.