Linear and Logistic Regression in TensorFlow
Linear and Logistic Regression in TensorFlow
Graphs and sessions
TF Ops: constants, variables, functions
TensorBoard
Lazy loading
Linear Regression: Predict life expectancy from birth rate
Let's start with a simple linear regression example. I hope you all are already familiar with linear regression. If not, you can read about it on Wikipedia. Basically, we'll be building a very simple neural network consisting of one layer to infer the linear relationship between one explanatory variable X and one dependent variable Y.
Problem
I recently came across the visualization of the relationship between birth rates and life expectancies of different countries around the world and found that fascinating. Basically, it looks like the more children you have, the younger you are going to die! You can play the visualization created by Google based on the data collected by the World Bank here.

My question is, can we quantify that relationship? In other words, if the birth rate of a country is and its life expectancy is , can we find a linear function f such that ? If we know that relationship, given the birth rate of a country, we can predict the life expectancy of that country.
For this problem, we will be using a subset of the World Development Indicators dataset collected by the World Bank. For simplicity, we will be using data from the year 2010 only. You can download the data from class's GitHub folder here.
Dataset Description
Name: Birth rate - life expectancy in 2010
X = birth rate. Type: float.
Y = life expectancy. Type: foat.
Number of datapoints: 190
Approach
First, assume that the relationship between the birth rate and the life expectancy is linear, which means that we can find w and b such that .
To find w and b (in this case, they are both scalars), we will use backpropagation through a one layer neural network. For the loss function, we will be using mean squared error. After each epoch, we measure the mean squared difference between the actual value Ys and the predicted values of Ys.
You can download the file examples/03_linreg_starter.py from the class's GitHub repo to give it a shot yourself. After you're done, you can compare with the solution below. You can also visit examples/03_linreg_placeholder.py on GitHub for the executable script.
|
import tensorflow as tf import utils DATA_FILE = "data/birth_life_2010.txt" # Step 1: read in data from the .txt file # data is a numpy array of shape (190, 2), each row is a datapoint data, n_samples = utils.read_birth_life_data(DATA_FILE) # Step 2: create placeholders for X (birth rate) and Y (life expectancy) X = tf.placeholder(tf.float32, name='X') Y = tf.placeholder(tf.float32, name='Y') # Step 3: create weight and bias, initialized to 0 w = tf.get_variable('weights', initializer=tf.constant(0.0)) b = tf.get_variable('bias', initializer=tf.constant(0.0)) # Step 4: construct model to predict Y (life expectancy from birth rate) # Step 5: use the square error as the loss function loss = tf.square(Y - Y_predicted, name='loss') # Step 6: using gradient descent with learning rate of 0.01 to minimize loss optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss) with tf.Session() # Step 7: initialize the necessary variables, in this case, w and b sess.run(tf.global_variables_initializer()) # Step 8: train the model for i in range(100): for x, y in data: # Session runs train_op to minimize loss sess.run(optimizer, feed_dict={X: x, Y:y}) # Step 9: output the values of w and b w_out, b_out = sess.run([w, b]) |
After training for 100 epochs, we got the average square loss to be 30.04 with w = -6.07, b = 84.93. It confirms our belief that there's a negative correlation between the birth rate and the life expectancy of a country. And no, it doesn't mean that having a child takes off 6 years of your life.

You can make other assumptions about the relationship between X and Y. For example, if we have a quadratic function:
To find w, u, and b for this model, we only have to add another variable u and change the formula for Y_predicted.
|
# Step 3: create variables: weights_1, weights_2, bias. All are initialized to 0 w = tf.get_variable('weights_1', initializer=tf.constant(0.0)) u = tf.get_variable('weights_2', initializer=tf.constant(0.0)) b = tf.get_variable('bias', initializer=tf.constant(0.0)) # Step 4: predict Y (number of theft) from the number of fire Y_predicted = w * X * X + X * u + b # Step 5: Profit! |
Control flow: Huber loss
Looking at the graph, we see that several outliers on the central bottom are outliers: they have low birth rate but also low life expectancy. Those outliers pull the fitted line towards them, making the model perform worse. One way to deal with outliers is to use Huber loss. Intuitively, squared loss has the disadvantage of giving too much weights to outliers (you square the difference - the larger the difference, the larger its square). Huber loss was designed to give less weight to outliers. Wikipedia has a pretty good article on it. Below is the Huber loss function:

To implement this in TensorFlow, we might be tempted to use something Pythonic such as:
|
if tf.abs(Y_predicted - Y) # do something |
However, this approach would only work if TensorFlow's eager execution were enabled, which we will learn about in the next lecture. If we use the current version, TensorFlow would soon notify us that "TypeError: Using a `tf.Tensor` as a Python `bool` is not allowed." We will need to use control flow ops defined by TensorFlow. For the full list of those ops, please visit the official documentation.
|
Control Flow Ops |
tf.count_up_to, tf.cond, tf.case, tf.while_loop, tf.group ... |
|
Comparison Ops |
tf.equal, tf.not_equal, tf.less, tf.greater, tf.where, ... |
|
Logical Ops |
tf.logical_and, tf.logical_not, tf.logical_or, tf.logical_xor |
|
Debugging Ops |
tf.is_finite, tf.is_inf, tf.is_nan, tf.Assert, tf.Print, ... |
To implement Huber loss, we can use either tf.greater, tf.less, or tf.cond. We will be using tf.cond since it's the most general. Other ops' usage is pretty similar.
|
tf.cond( pred, true_fn=None, false_fn=None, ...) |
This basically means that if the condition is true, use the true function. Else, use the false function.
|
def huber_loss(labels, predictions, delta=14.0): residual = tf.abs(labels - predictions) def f1(): def f2(): return tf.cond(residual < delta, f1, f2) |
With Huber loss, we found w: -5.883589, b: 85.124306. The graph compares the fitted line obtained by squared loss and Huber loss.

Which model performs better? Ah, we should have had a test set.
tf.data
You can visit examples/03_linreg_dataset.py on GitHub for the executable script.
According to Derek Murray in his introduction to tf.data, a nice thing about placeholder and feed_dicts is that they put the data processing outside TensorFlow, making it easy to shuffle, batch, and generate arbitrary data in Python. The drawback is that this mechanism can potentially slow down your program. Users often end up processing their data in a single thread and creating data bottleneck that slows execution down.
TensorFlow also offers queues as another option to handle your data. This provides performance as it lets you do pipelining, threading and reduces the time loading data into placeholders. However, queues are notorious for being difficult to use and prone to crashing.
Recently, demand for a better way to handle your data has been all the rage, and TensorFlow answers with tf.data module. It promises to be faster than placeholders and easier to use than queues, and doesn't crash. So how does this magical thing work?
Notice that in our linear regression, we stored the input data in a numpy array called data, each row of this numpy array is a pair value for (x, y), corresponding to a data point. To import this data into our TensorFlow model, we created placeholders for x (feature) and y (label). We then iterate through each data point with a for loop in step 8 and feed it into the placeholders with a feed_dict. We can, of course, use batches of data points instead of individual data points, but the key here is that the process of feeding the data from this numpy array to the TensorFlow model is slow and can get in the way of other execution of other ops.
|
# Step 1: read in data from the .txt file # data is a numpy array of shape (190, 2), each row is a datapoint data, n_samples = utils.read_birth_life_data(DATA_FILE) # Step 2: create placeholders for X (birth rate) and Y (life expectancy) X = tf.placeholder(tf.float32, name='X') Y = tf.placeholder(tf.float32, name='Y') ... with tf.Session() ... # Step 8: train the model for i in range(100): for x, y in data: # Session runs train_op to minimize loss sess.run(optimizer, feed_dict={X: x, Y:y}) |
With tf.data, instead of storing our input data in a non-TensorFlow object, we store it in a tf.data.Dataset object. We can create a Dataset from tensors with:
|
tf.data.Dataset.from_tensor_slices((features, labels)) |
features and labels are supposed to be tensors, but remember that since TensorFlow and Numpy are seamlessly integrated, they can be NumPy arrays. We can initialize our dataset as followed:
|
dataset = tf.data.Dataset.from_tensor_slices((data[:,0], data[:,1])) |
Printing out type and shape of entries in the dataset for sanity check:
|
print(dataset.output_types) # >> (tf.float32, tf.float32) print(dataset.output_shapes) # >> (TensorShape([]), TensorShape([])) |
You can also create a tf.data.Dataset from files using one of TensorFlow's file format parsers, all of them have striking similarity to the old DataReader.
- tf.data.TextLineDataset(filenames): each of the line in those files will become one entry. It's good for datasets whose entries are delimited by newlines such as data used for machine translation or data in csv files.
- tf.data.FixedLengthRecordDataset(filenames): each of the data point in this dataset is of the same length. It's good for datasets whose entries are of a fixed length, such as CIFAR or ImageNet.
- tf.data.TFRecordDataset(filenames): it's good to use if your data is stored in tfrecord format.
Example:
|
dataset = tf.data.FixedLengthRecordDataset([file1, file2, file3, |
After we have turned our data into a magical Dataset object, we can iterate through samples in this Dataset using an iterator. An iterator iterates through the Dataset and returns a new sample or batch each time we call get_next(). Let's start with make_one_shot_iterator(), we'll find out what it is in a bit. The iterator is of the class tf.data.Iterator.
|
iterator = dataset.make_one_shot_iterator() X, Y = iterator.get_next() |
Each time we execute ops X, Y, we get a new data point.
|
with tf.Session() print(sess.run([X, Y])) # >> [1.822, 74.82825] print(sess.run([X, Y])) # >> [3.869, 70.81949] print(sess.run([X, Y])) # >> [3.911, 72.15066] |
Now we can just compute Y_predicted and losses from X and Y just like you did with placeholders. The difference is that when you execute your graph, you no longer need to supplement data through feed_dict.
|
for i in range(100): total_loss = 0 try: while sess.run([optimizer]) except tf.errors.OutOfRangeError: pass |
We have to catch the OutOfRangeError because miraculously, TensorFlow doesn't automatically catch it for us. If we run this code, we will see that we only get non zero loss in the first epoch. After that, the loss is always 0. It's because dataset.make_one_shot_iterator() literally gives you only one shot. It's fast to use -- you don't have to initialize it -- but it can be used only once. After one epoch, you reach the end of your data and you can't re-initialize it for the next epoch.
To use for multiple epochs, we use dataset.make_initializable_iterator(). At the beginning of each epoch, you have to re-initialize your iterator.
|
iterator = dataset.make_initializable_iterator() ... for i in range(100): sess.run(iterator.initializer) total_loss = 0 try: while sess.run([optimizer]) except tf.errors.OutOfRangeError: pass |
With tf.data.Dataset, you can batch, shuffle, repeat your data with just one command. You can also map each element of your dataset to transform it in a specific way to create a new dataset.
|
dataset = dataset.shuffle(1000) dataset = dataset.repeat(100) dataset = dataset.batch(128) # convert each element of dataset to one_hot vector |
Does tf.data really perform better?
To compare the performance of tf.data with that of placeholders, I ran each model 100 times and calculated the average time each model took. On my Macbook Pro with 2.7 GHz Intel Core i5, the model with placeholder took on average 9.05271519 seconds, while the model with tf.data took on average 6.12285947 seconds. tf.data improves the performance by 32.4% compared to placeholders!
So yes, tf.data does deliver. It makes importing and processing data easier while making our program run faster.
Optimizers
In the code above, there are two lines that haven't been explained.
|
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss) sess.run([optimizer]) |
I remember the first time I ran into code similar to these, I was very confused.
- Why is optimizer in the fetches list of tf.Session.run()?
- How does TensorFlow know what variables to update?
optimizer is an op whose job is to minimize loss. To execute this op, we need to pass it into the list of fetches of tf.Session.run(). When TensorFlow executes optimizer, it will execute the part of the graph that this op depends on. In this case, we see that optimizer depends on loss, and loss depends on inputs X, Y, as well as two variables weights and bias.

From the graph, you can see that the giant node GradientDescentOptimizer depends on 3 nodes: weights, bias, and gradients (which are automatically taken care of for us).
GradientDescentOptimizer means that our update rule is gradient descent. TensorFlow does auto differentiation for us, then update the values of w and b to minimize the loss. Autodiff is amazing!
By default, the optimizer trains all the trainable variables its objective function depends on. If there are variables that you do not want to train, you can set the keyword trainable=False when you declare a variable. One example of a variable you don't want to train is the variable global_step, a common variable you will see in many TensorFlow model to keep track of how many times you've run your model.
|
global_step = tf.Variable(0, trainable=False, dtype=tf.int32) learning_rate = increment_step = global_step.assign_add(1) optimizer = tf.train.GradientDescentOptimizer(learning_rate) |
|
tf.Variable( initial_value=None, trainable=True, collections=None, validate_shape=True, caching_device=None, name=None, variable_def=None, dtype=None, expected_shape=None, import_scope=None, constraint=None ) tf.get_variable( name, shape=None, dtype=None, initializer=None, regularizer=None, trainable=True, collections=None, caching_device=None, partitioner=None, validate_shape=True, use_resource=None, custom_getter=None, constraint=None ) |
You can also ask your optimizer to take gradients of specific variables. You can also modify the gradients calculated by your optimizer.
|
# create an optimizer. optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1) # compute the gradients for a list of variables. grads_and_vars = optimizer.compute_gradients(loss, # grads_and_vars is a list of tuples (gradient, variable). Do whatever you # need to the 'gradient' part, for example, subtract each of them by 1. subtracted_grads_and_vars = # ask the optimizer to apply the subtracted gradients. optimizer.apply_gradients(subtracted_grads_and_vars) |
You can also prevent certain tensors from contributing to the calculation of the derivatives with respect to a specific loss with tf.stop_gradient.
|
stop_gradient( input, name=None ) |
This is very useful in situations when you want to freeze certain variables during training. Here are some examples given by TensorFlow's official documentation.
- When you train a GAN (Generative Adversarial Network) where no backprop should happen through the adversarial example generation process.
- The EM algorithm where the M-step should not involve backpropagation through the output of the E-step.
The optimizer classes automatically compute derivatives on your graph, but you can explicitly ask TensorFlow to calculate certain gradients with tf.gradients.
|
tf.gradients( ys, xs, grad_ys=None, name='gradients', colocate_gradients_with_ops=False, gate_gradients=False, aggregation_method=None, stop_gradients=None ) |
This method constructs symbolic partial derivatives of sum of ys w.r.t. x in xs. ys and xs are each a Tensor or a list of tensors. grad_ys is a list of Tensor, holding the gradients received by the ys. The list must be the same length as ys.
Technical detail: This is especially useful when training only parts of a model. For example, we can use tf.gradients() to take the derivative G of the loss w.r.t. to the middle layer. Then we use an optimizer to minimize the difference between the middle layer output M and M + G. This only updates the lower half of the network.
List of optimizers
GradientDescentOptimizer is not the only update rule that TensorFlow supports. Here is the list of optimizers that TensorFlow supports, as of 1/17/2017. The names are self-explanatory. You can visit theofficial documentation for more details:
tf.train.Optimizer
tf.train.GradientDescentOptimizer
tf.train.AdadeltaOptimizer
tf.train.AdagradOptimizer
tf.train.AdagradDAOptimizer
tf.train.MomentumOptimizer
tf.train.AdamOptimizer
tf.train.FtrlOptimizer
tf.train.ProximalGradientDescentOptimizer
tf.train.ProximalAdagradOptimizer
tf.train.RMSPropOptimizer
Sebastian Ruder, a PhD candidate at the Insight Research Centre for Data Analytics did a pretty great comparison of these optimizers in his blog post. If you're too lazy to read, here is the conclusion:
"RMSprop is an extension of Adagrad that deals with its radically diminishing learning rates. It is identical to Adadelta, except that Adadelta uses the RMS of parameter updates in the numerator update rule. Adam, finally, adds bias-correction and momentum to RMSprop. Insofar, RMSprop, Adadelta, and Adam are very similar algorithms that do well in similar circumstances. Kingma et al. [15] show that its bias-correction helps Adam slightly outperform RMSprop towards the end of optimization as gradients become sparser. Insofar, Adam might be the best overall choice."
TL;DR: Use AdamOptimizer.
Discussion questions
What are some of the real world problems that we can solve using linear regression? Can you write a quick program to do so?
Logistic Regression with MNIST
Let's build a logistic regression model in TensorFlow solving the good old classifier on the MNIST database.
The MNIST (Mixed National Institute of Standards and Technology database) is one of the most popular databases used for training various image processing systems. It is a database of handwritten digits. The images look like this:

Each image is 28 x 28 pixels. You can flatten each image to be a 1-d tensor of size 784. Each comes with a label from 0 to 9. For example, images on the first row is labelled as 0, the second as 1, and so on. The dataset is hosted on Yann Lecun's website.
TF Learn (the simplified interface of TensorFlow) has a script that lets you load the MNIST dataset from Yann Lecun's website and divide it into train set, validation set, and test set.
|
from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('data/mnist', one_hot=True) |
|
One-hot encoding In digital circuits, one-hot refers to a group of bits among which the legal combinations of values are only those with a single high (1) bit and all the others low (0). In |
input_data.read_data_sets('data/mnist', one_hot=True) returns an instance of learn.datasets.base.Datasets, which contains three generators to 55,000 data points of training data (mnist.train), 10,000 points of test data (mnist.test), and 5,000 points of validation data (mnist.validation). You get the samples of these datasets by calling next_batch(batch_size), for example, mnist.train.next_batch(batch_size) with a batch_size of your choice. However, in real life, we often don't have access to an off the shelf data parser I thought it'd be nice for us to just read in the MNIST data ourselves. It's also a good practice because in your real life work, you're likely to have to write your own data parser.
I've already written the code for downloading and parsing MNIST data into numpy arrays in the file utils.py. All you need to do in your program is:
|
mnist_folder = utils.download_mnist(mnist_folder) train, val, test = utils.read_mnist(mnist_folder, flatten=True) |
We choose flatten=True because we want each image to be flattened into a 1-d tensor. Each of train, val, and test in this case is a tuple of NumPy arrays, the first is a NumPy array of images, the second of labels. We need to create two Dataset objects, one for train set and one for test set (in this example, we won't be using val set).
|
train_data = tf.data.Dataset.from_tensor_slices(train) # train_data = train_data.shuffle(10000) # if you want to shuffle your data test_data = tf.data.Dataset.from_tensor_slices(test) |
The construction of the logistic regression model is pretty similar to the linear regression model. However, now we have A LOT more data. If we calculate gradient after every single data point it'd be painfully slow. Fortunately, we can process the data in batches.
|
train_data = train_data.batch(batch_size) test_data = test_data.batch(batch_size) |
The next step is to create an iterator to get samples from the two datasets. In the linear regression example, we used only the train set, so it was okay to create an iterator for that dataset and just draw samples from that dataset. When we have more than one dataset, if we have one iterator for each dataset, we would need to build one graph for each iterator! A better way to do it is to create one single iterator and initialize it with a dataset when we need to draw data from that dataset.
|
iterator = tf.data.Iterator.from_structure(train_data.output_types, train_data.output_shapes) img, label = iterator.get_next() train_init = iterator.make_initializer(train_data) # initializer for train_data test_init = iterator.make_initializer(test_data) # initializer for test_data with tf.Session() ... for i in range(n_epochs): sess.run(train_init) # drawing samples from train_data try: while _, l = sess.run([optimizer, loss]) except tf.errors.OutOfRangeError: pass # test the model sess.run(test_init) # drawing samples from test_data try: while sess.run(accuracy) except tf.errors.OutOfRangeError: pass |
Similar to linear regression, you can download the starter file examples/03_logreg_starter.py from the class's GitHub repo and give it a shot. You can see the solution at examples/03_logreg.py.
Running on my Mac, the batch version of the model with batch size 128 runs in 1 second, while the non-batch model runs in 30 seconds! Note that larger batch size typically requires more epochs since it does fewer update steps. See "mini-batch size" in Bengio's practical tips. Larger batch size also requires more memory.
We achieved the accuracy of 91.34% after 30 epochs. This is about as good as we can get from a linear classifier.
Shuffling can affect performance: without shuffling, the accuracy is consistently at 91.34%. With shuffle, the accuracy fluctuates between 88% to 93%.
Let's see what our graph looks like on TensorBoard.

WOW
I know. That's why we'll learn how to structure our model in the next lecture!
Linear and Logistic Regression in TensorFlow的更多相关文章
- [Scikit-learn] 1.1 Generalized Linear Models - Logistic regression & Softmax
二分类:Logistic regression 多分类:Softmax分类函数 对于损失函数,我们求其最小值, 对于似然函数,我们求其最大值. Logistic是loss function,即: 在逻 ...
- Matlab实现线性回归和逻辑回归: Linear Regression & Logistic Regression
原文:http://blog.csdn.net/abcjennifer/article/details/7732417 本文为Maching Learning 栏目补充内容,为上几章中所提到单参数线性 ...
- TensorFlow 学习笔记(1)----线性回归(linear regression)的TensorFlow实现
此系列将会每日持续更新,欢迎关注 线性回归(linear regression)的TensorFlow实现 #这里是基于python 3.7版本的TensorFlow TensorFlow是一个机器学 ...
- 机器学习---三种线性算法的比较(线性回归,感知机,逻辑回归)(Machine Learning Linear Regression Perceptron Logistic Regression Comparison)
最小二乘线性回归,感知机,逻辑回归的比较: 最小二乘线性回归 Least Squares Linear Regression 感知机 Perceptron 二分类逻辑回归 Binary Logis ...
- SparkMLlib之 logistic regression源码分析
最近在研究机器学习,使用的工具是spark,本文是针对spar最新的源码Spark1.6.0的MLlib中的logistic regression, linear regression进行源码分析,其 ...
- Logistic Regression vs Decision Trees vs SVM: Part II
This is the 2nd part of the series. Read the first part here: Logistic Regression Vs Decision Trees ...
- Logistic Regression Vs Decision Trees Vs SVM: Part I
Classification is one of the major problems that we solve while working on standard business problem ...
- 统计学习方法笔记 Logistic regression
logistic distribution 设X是连续随机变量,X服从逻辑斯谛分布是指X具有下列分布函数和密度函数: 式中,μ为位置参数,γ>0为形状参数. 密度函数是脉冲函数 分布函数是一条S ...
- Logistic Regression and Gradient Descent
Logistic Regression and Gradient Descent Logistic regression is an excellent tool to know for classi ...
随机推荐
- bzoj 4596: [Shoi2016]黑暗前的幻想乡【容斥原理+矩阵树定理】
真是简单粗暴 把矩阵树定理的运算当成黑箱好了反正我不会 这样我们就可以在O(n^3)的时间内算出一个无向图的生成树个数了 然后题目要求每个工程队选一条路,这里可以考虑容斥原理:全选的方案数-不选工程队 ...
- bzoj 2015: [Usaco2010 Feb]Chocolate Giving【spfa】
因为是双向边,所以相当于两条到1的最短路和,先跑spfa然后直接处理询问即可 #include<iostream> #include<cstdio> #include<q ...
- org.apache.poi.hssf.util.Region
从POI 3.18开始被Deprecated,在3.20版本中被移除了,所以3.20以前的都有 为了避免这个问题,用CellRangeAddress代替Region,其用法相同
- POJ 2187 凸包+旋转卡壳
思路: 求个凸包 旋转卡壳一下 就求出来最远点对了 注意共线情况 也就是说 凸包如果有一堆点共线保留端点即可 //By SiriusRen #include <cmath> #incl ...
- 牛客练习赛17-A-长方体
题目描述 给出共享长方体一个顶点的三个面的面积,求它十二条边的边长和. 输入描述: 一行三个整数a, b, c表示面积(1 <= a, b, c <= 10000). 输出描述: 一行一个 ...
- 368 Largest Divisible Subset 最大整除子集
给出一个由无重复的正整数组成的集合, 找出其中最大的整除子集, 子集中任意一对 (Si, Sj) 都要满足: Si % Sj = 0 或 Sj % Si = 0.如果有多个目标子集,返回其中任何一个均 ...
- 233 Number of Digit One 数字1的个数
给定一个整数 n,计算所有小于等于 n 的非负数中数字1出现的个数. 例如: 给定 n = 13, 返回 6,因为数字1出现在下数中出现:1,10,11,12,13. 详见:https://leetc ...
- 290 Word Pattern 单词模式
给定一种 pattern(模式) 和一个字符串 str ,判断 str 是否遵循这种模式.这里的 遵循 指完全匹配,例如在pattern里的每个字母和字符串 str 中的每个非空单词存在双向单映射关系 ...
- 总结esp8266刷Python的完整的步骤(终极总结)
2018-04-0319:12:02 从玩microPython 到现在,一路荆棘一路坎坷. 不知道只有我遇到这样的问题还是microPython太不稳定,还是我买的板子太糙.总之遇到了太多问题了. ...
- 由DB2分页想到的,关于JDBC ResultSet 处理大数据量
最近在处理DB2 ,查询中,发现如下问题.如果一个查询 count(*),有几十万行,分页如何实现 select row_number() over (order by fid desc ) as r ...