Calculating paystring for loan data - c++

Example:
Input: cpi = 100.0, payments = [100.0, 94.0, 90.0, 100.0, 200.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0 ]
Output: paystring = [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
Explanation: Since the first payment was 100.0 and that is greater than or equal to cpi - 5.0 (95.0) then the first element in the output is 0. Then the next element is 1 since 94.0 is less than cpi - 5.0 (95.0) i.e. missed a payment, then since the next element 90.0 is less than cpi - 5.0 (95.0) i.e. missed another payment than now we are at 2 (or 2 total missed payments). Then in the next element we had 100 then that counts as 1 payment made so now we made that payment that was due but we still didn't cover the other two payments from the prior month so we are still at 2. Then the process continues.
I have this so far:
double cpi = 100.0;
std::vector<double> payments = { 100.0, 94.0, 90.0, 100.0, 200.0, 300.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0 };
std::vector<int> paystring(payments.size(), 0);
int count = 0;
for (int i = 0; i < payments.size(); ++i) {
if (payments[i] <= cpi - 5.0) {
paystring[i] = ++count;
}
else {
paystring[i] = count;
}
}
for (auto it : paystring)
std::cout << it << " ";
Although, this is not correct since it fails to update count when I made lets say the full payment or more than the due amount (cpi). I just want to know what I need to change in my logic to make this work. Let me know if the example provided is unclear.
For example say I have
Input: cpi = 100.0, payments = [100.0, 94.0, 90.0, 100.0, 200.0, 100.0, 300.0, 100.0, 100.0, 100.0, 100.0, 100.0 ]
Output: [0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0]
But I get
[0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
Here is a few more examples that are correct:

You have a condition that if payment is too low, penalty is added, the customer is one month behind.
Add another condition: If over payment is made, for example $200, you want to give customer credit, that puts the customer one month ahead. Then add a condition that the customer is not ahead by a negative count.
std::vector<double> payments = {
100, 94, 90, 100, 200, 100, 300, 100, 100, 100, 100, 100
//"0 1 1 0 -1 0 -2 0 0 0 0 0 <-penalty
//"0 1 2 2 1 1 0 0 0 0 0 0 <-penalty sum
};
double cpi = 100.0;
for(int i = 0; i < payments.size(); ++i)
{
double payment = payments[i];
if(payment <= (cpi - 5.0))
{
//one month behind on payment
count++;
}
while((payment > cpi) && count)
{
//customer made large payment.
//allow count to decrease.
//but count cannot be less than zero
count--;
payment -= cpi;
}
paystring[i] = count;
}
Ouput for 100, 94, 90, 100, 200, 100, 100, 100, 100, 100, 100, 100:
0 1 2 2 2 2 2 2 2 2 2 2 //expected output
0 1 2 2 1 1 1 1 1 1 1 1 //result
Ouput for 100, 94, 90, 100, 200, 100, 300, 100, 100, 100, 100, 100:
0 1 2 2 1 0 0 0 0 0 0 0 //expected output
0 1 2 2 1 1 0 0 0 0 0 0 //result
My output is not the same, maybe the expected output is incorrect or you left something out. Note the 6th payment is 100, so there shouldn't be any change for that index.

Related

c++ print formatted 2D array

I am trying to print a 2d matrix in c++. I have a 2D array of integers. The output looks like this:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60
0 0 0 0 0 0 0 0 0 0 60 60 60 60 60 60 60 60 60 60 100 100 100 100 100 100 100 100 100 100 160
My code simply does 2 loops and adds an space after each number (and a newline after every row). Is there an easy way to print nicely formatted matrix in cpp. Something that would be more readable like so:
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 60 60 60 60 60
0 0 0 0 0 0 60 60 100 100 160
Code:
for(int i = 0; i <= n ; i++){
for(int w = 0; w <= W ; w++){
std:cout<<some_array[i][w]<<" ";
}
std::cout << std::endl;
}
This overload of the output stream operator will do the formatting for you.
And then the code where you do the output will look quite clean.
#include <iostream>
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
std::ostream& operator<<(std::ostream& os, type_t (&arr)[rows_v][cols_v])
{
// loop over the rows
for (const auto& row : arr)
{
// to print a comma between values
bool comma{ false };
// loop over the values in the row
for (const auto& value : row)
{
if (comma) os << ", ";
os << value;
comma = true;
}
os << "\n";
}
return os;
}
int main()
{
int arr[2][3]{{0,1,2},{4,5,6}};
std::cout << arr << "\n";
return 0;
}
Quick code that does this, could be made better:
#include <iostream>
#include <string>
int main()
{
int maxwidth = 0;
int sz;
std::string s;
int K[3][31] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 160}};
for (int i = 0; i < 3; i++)
{
for (int w = 0; w < 31; w++)
{
s = std::to_string(K[i][w]);
sz = s.size();
maxwidth = std::max(maxwidth, sz);
}
}
maxwidth++; // we need to print 1 extra space than maxwidth
for (int i = 0; i < 3; i++)
{
for (int w = 0; w < 31; w++)
{
std::cout << K[i][w];
s = std::to_string(K[i][w]);
sz = (maxwidth - s.size());
while (sz--)
std::cout << " ";
}
std::cout << std::endl;
}
return 0;
}
Output:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60
0 0 0 0 0 0 0 0 0 0 60 60 60 60 60 60 60 60 60 60 100 100 100 100 100 100 100 100 100 100 160

Python Pandas: Create Groups by Range using map

I have a large data set where I am looking to create groups based upon cumulative sum percent of the total. I have gotten this to work by using the map function see below code. Is there a better way to do this say if I wanted to make my groups even more granular? So for example now am looking at 5% increments...what if want to look at 1 % increments. Wondering if there is another way where I don't have to explicitly enter them into my "codethem" function.
def codethem(dl):
if dl < .05 : return '5'
elif .05 < dl <= .1: return '10'
elif .1 < dl <= .15: return '15'
elif .15 < dl <= .2: return '20'
elif .2 < dl <= .25: return '25'
elif .25 < dl <= .3: return '30'
elif .3 < dl <= .35: return '35'
elif .35 < dl <= .4: return '40'
elif .4 < dl <= .45: return '45'
elif .45 < dl <= .5: return '50'
elif .5 < dl <= .55: return '55'
elif .55 < dl <= .6: return '60'
elif .6 < dl <= .65: return '65'
elif .65 < dl <= .7: return '70'
elif .7 < dl <= .75: return '75'
elif .75 < dl <= .8: return '80'
elif .8 < dl <= .85: return '85'
elif .85 < dl <= .9: return '90'
elif .9 < dl <= .95: return '95'
elif .95 < dl <= 1: return '100'
else: return 'None'
my_df['code'] = my_df['sales_csum_aspercent'].map(code them)
Thank you!
there is a special method for that - pd.cut()
Demo:
create random DF:
In [393]: df = pd.DataFrame({'a': np.random.rand(10)})
In [394]: df
Out[394]:
a
0 0.860256
1 0.399267
2 0.209185
3 0.773647
4 0.294845
5 0.883161
6 0.985758
7 0.559730
8 0.723033
9 0.126226
we should specify bins when calling pd.cut():
In [404]: np.linspace(0, 1, 11)
Out[404]: array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])
In [395]: pd.cut(df.a, bins=np.linspace(0, 1, 11))
Out[395]:
0 (0.8, 0.9]
1 (0.3, 0.4]
2 (0.2, 0.3]
3 (0.7, 0.8]
4 (0.2, 0.3]
5 (0.8, 0.9]
6 (0.9, 1]
7 (0.5, 0.6]
8 (0.7, 0.8]
9 (0.1, 0.2]
Name: a, dtype: category
Categories (10, object): [(0, 0.1] < (0.1, 0.2] < (0.2, 0.3] < (0.3, 0.4] ... (0.6, 0.7] < (0.7, 0.8] < (0.8, 0.9] < (0.9, 1]]
if we want to have a custom labels, we should explicitly specify them:
In [401]: bins = np.linspace(0,1, 11)
NOTE: bin labels must be one fewer than the number of bin edges
In [402]: labels = (bins[1:]*100).astype(int)
In [412]: labels
Out[412]: array([ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
In [403]: pd.cut(df.a, bins=bins, labels=labels)
Out[403]:
0 90
1 40
2 30
3 80
4 30
5 90
6 100
7 60
8 80
9 20
Name: a, dtype: category
Categories (10, int64): [10 < 20 < 30 < 40 ... 70 < 80 < 90 < 100]
Lets do it with the 5% step
In [419]: bins = np.linspace(0, 1, 21)
In [420]: bins
Out[420]: array([ 0. , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 , 0.35, 0.4 , 0.45, 0.5 , 0.55, 0.6 , 0.65, 0.7 , 0.75, 0.8 , 0.8
5, 0.9 , 0.95, 1. ])
In [421]: labels = (bins[1:]*100).astype(int)
In [422]: labels
Out[422]: array([ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100])
In [423]: pd.cut(df.a, bins=bins, labels=labels)
Out[423]:
0 90
1 40
2 25
3 80
4 30
5 90
6 100
7 60
8 75
9 15
Name: a, dtype: category
Categories (20, int64): [5 < 10 < 15 < 20 ... 85 < 90 < 95 < 100]

calculate gradient directions

I want calculate angles of gradients from depth map and group it for some directions (8 sectors)
But my function calculates only first 3 directions
cv::Mat calcAngles(cv::Mat dimg)//dimg is depth map
{
const int directions_num = 8;//number of directions
const int degree_grade = 360;
int range_coeff = 255 / (directions_num + 1);//just for visualize
cv::Mat x_edge, y_edge, full_edge, angles;
dimg.copyTo(x_edge);
dimg.copyTo(y_edge);
dimg.copyTo(full_edge);
//compute gradients
Sobel( dimg, x_edge, CV_8U, 1, 0, 5, 1, 19, 4 );
Sobel( dimg, y_edge, CV_8U, 0, 1, 5, 1, 19, 4 );
Sobel( dimg, full_edge, CV_8U, 1, 1, 5, 1, 19, 4 );
float freq[directions_num + 1];//for collect direction's frequency
memset(freq, 0, sizeof(freq));
angles = cv::Mat::zeros(dimg.rows, dimg.cols, CV_8U);//store directions here
for(int i = 0; i < angles.rows; i++)
{
for(int j = 0; j < angles.cols; j++)
{
angles.at<uchar>(i, j) = (((int)cv::fastAtan2(y_edge.at<uchar>(i, j), x_edge.at<uchar>(i, j))) / (degree_grade/directions_num) + 1
) * (dimg.at<uchar>(i, j) ? 1 : 0);//fastatan returns values from 0 to 360, if i not mistaken. I want group angles by directions_num sectors. I use first 'direction' (zero value) for zero values from depth map (zero value at my depth map suggest that it is bad pixel)
freq[angles.at<uchar>(i, j)] += 1;
}
}
for(int i = 0; i < directions_num + 1; i++)
{
printf("%2.2f\t", freq[i]);
}
printf("\n");
angles *= range_coeff;//for visualization
return angles;
}
Out from one of the frames:
47359.00 15018.00 8199.00 6224.00 0.00 0.00 0.00 0.00 0.00
(first value is "zero pixel", next is number of gradients in n-place but only 3 are not zero)
Visualization
Is there way out? Or these result is OK?
PS Sorry for my writing mistakes. English in not my native language.
You used CV_8U type for Sobel output. It is unsigned integer 8 bit. So it can store only positive values. That's why fastAtan2 returns less or equal than 90. Change type to CV_16S and use short type for accessing the elements:
cv::Sobel(dimg, x_edge, CV_16S, 1, 0, 5, 1, 19, 4);
cv::Sobel(dimg, y_edge, CV_16S, 0, 1, 5, 1, 19, 4);
cv::fastAtan2(y_edge.at<short>(i, j), x_edge.at<short>(i, j))

Comparison between GLfloats

So, I am doing a little code for opengl that picks the color of one square and sum 0.01 on his value, so the color will be more shining. I have values of colors for each square in one array , and I got one variable that holds the value of the maximum one element of the color can go, in this case this value is one.
This is part of the function
for(GLint i = 0; i < 3; i++) {
if(colors[selectedSquare][i] > 0) {
colors[selectedSquare][i] += 0.01;
if(colors[selectedSquare][i] == maxColor) {
flag = false;
}
}
}
I call this function in glutTimerFunc, and improve the value of the color in 0.01 for each time. When the value of the color goes egual 1 (the maxColor) i start to reducing the color in other part of the function.
The problem here is that the comparison
(colors[selectedSquare][i] == maxColor)
Never gets true, I made some output to check and this is what I got
colors[selectedSquare][i] value = 0.99 size = 4
maxColor value = 1 size = 4
(colors[selectedSquare][i] == maxColor) is 0
colors[selectedSquare][i] value = 1 size = 4
maxColor value = 1 size = 4
(colors[selectedSquare][i] == maxColor) is 0
colors[selectedSquare][i] value = 1.01 size = 4
maxColor value = 1 size = 4
(colors[selectedSquare][i] == maxColor) is 0
colors[selectedSquare][i] value = 1.02 size = 4
maxColor value = 1 size = 4
(colors[selectedSquare][i] == maxColor) = 0
But the interesting thing starts here, when I change the comparison to
((int)colors[selectedSquare][i] == maxColor)
I get this output
colors[selectedSquare][i] value = 0.99 size = 4
maxColor value = 1 size = 4
(colors[selectedSquare][i] == maxColor) is 0
colors[selectedSquare][i] value = 1 size = 4
maxColor value = 1 size = 4
(colors[selectedSquare][i] == maxColor) is 0
colors[selectedSquare][i] value = 1.01 size = 4
maxColor value = 1 size = 4
(colors[selectedSquare][i] == maxColor) is 1
colors[selectedSquare][i] value = 1.02 size = 4
maxColor value = 1 size = 4
(colors[selectedSquare][i] == maxColor) is 1
I measure the size using sizeof(), and the declaration of colors and maxColor is like that
GLfloat (Memoria::colors)[9][3] = {
{ 0.80, 0.80, 0.00 },
{ 0.00, 0.80, 0.80 },
{ 0.80, 0.00, 0.00 },
{ 0.00, 0.80, 0.00 },
{ 0.00, 1.00, 1.00 },
{ 1.00, 0.00, 0.00 },
{ 1.00, 0.00, 1.00 },
{ 1.00, 1.00, 0.00 },
{ 1.00, 1.00, 1.00 },
};
const GLfloat maxColor;
Both belong to the same class, but colors is static.
Hope someone knows the problem.
Directly comparing doubles is a bad idea. You could use >= instead of == or do something like
if(fabs(colors[selectedSquare][i] - maxColor) > delta)
where delta is a precision you want to use.
Your problem is - doubles are never stored exactly as you seem to expect them to be. There are always fluctuations at the end of the number far beyond the comma separated part.

Printing values of keypoint descriptor matrix opencv

I'm having some trouble printing the values of the descriptor matrix obtained through the use of the 'compute' method of any opencv descriptor extractor. I want to print the descriptor of a feature to a file one by one, but always when I access some element of the descriptor matrix with 'at', I receive a different value for that element. The following is a 'for' loop I used to test the output value of the descriptor matrix when using 'at':
for(int i=0; i<nF; i++){
if(lpx != keypoints[i].pt.x && lpy != keypoints[i].pt.y){
usedFeatures++;
cerr << descriptors.row(i) << endl << endl; // printing row of descriptor matrix
fileS << keypoints[i].pt.y << " " << keypoints[i].pt.x << " ";
fileS << keypoints[i].size << " " << keypoints[i].angle << endl;
if(i == nF - 2){
//printing subvector of descriptor matrix made of the element at row i and col 0
cerr << "get row i, col 0 " << descriptors.row(i).col(0) << endl;
//same as before just inverting the order of access
cerr << "get col 0, row i: " << descriptors.col(0).row(i) << endl;
//printing the value of the element with 'at'
cerr << (int)descriptors.at<uchar>(i, 0);
//creating a new int and giving it the value of element (i, 0) of descriptor matrix. Should be the same
//value shown on the subvector before
int test = descriptors.at<uchar>(i, 0);
//printing value of element
cerr << "i, 0: " << test << endl;
}
The second 'if' is a test 'if' I made to see the values printed when accessing the elements of the descriptors. Now, printed by the
cerr << descriptors.row(i) << endl << endl;
at the nF - 2 iteraction, I have the following result:
[20, 11, 0, 18, 51, 3, 0, 3, 133, 50, 0, 0, 0, 0, 0, 11, 133, 18, 0, 0, 0, 0, 0, 3,
119, 2, 0, 0, 0, 0, 0, 2, 19, 5, 0, 4, 55, 27, 1, 1, 133, 25, 0, 1, 4, 1, 0, 22, 133,
18, 0, 0, 0, 0, 0, 14, 131, 13, 1, 0, 0, 0, 0, 1, 12, 1, 0, 1, 56, 133, 25, 13, 133,
14, 0, 0, 3, 8, 20, 80, 133, 38, 0, 0, 0, 0, 0, 51, 106, 11, 1, 0, 0, 0, 0, 23, 0, 0,
0, 0, 19, 126, 70, 11, 23, 0, 0, 0, 0, 9, 83, 133, 53, 1, 0, 0, 0, 0, 2, 133, 26,
3, 2, 0, 0, 0, 0, 28]
And as expected, the first two prints inside the second 'if':
cerr << "get row i, col 0 " << descriptors.row(i).col(0) << endl;
cerr << "get col 0, row i: " << descriptors.col(0).row(i) << endl;
give me [20]
But the other two prints
cerr << (int)descriptors.at<uchar>(i, 0);
and
int test = descriptors.at<uchar>(i, 0);
cerr << "i, 0: " << test << endl;
give me 0 instead of 20. The complete result I had for line nF-2 I showed before, when accessing the elements with 'at' and printing them was:
0 0 160 65 0 0 48 65 0 0 0 0 0 0 144 65 0 0 76 66
0 0 64 64 0 0 0 0 0 0 64 64 0 0 5 67 0 0 72 66
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 48 65 0 0 5 67 0 0 144 65 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 64 0 0 238 66
0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 64
Which is completely different from what I was expecting. I've tried a lot of things already: casting with float, double, unsigned int instead of only int, and assigning to variables of those types as well; converting the matrix before printing it, copying the matrix then converting, creating the descriptors matrix with a different type...but none of them worked. I suspect it has something to do with the type of the descriptors matrix, although I'm almost sure it has the uchar type (I checked with elemSize)
Thanks in advance, and sorry for my english and the size of the question.
Found the answer. It was indeed a type problem. The type of descriptor matrix returned by isn't uchar like I thought, it is actually float. Getting the value with
(float)descriptors.at<float>(i, 0);
gives me the right value. Funny thing is I could swear I tried it for float before, and it didn't work. I must've tried it only for int, double and unsigned int.
This does not answer why your problem happens, but I remember having similar issues when trying to access my descriptor values.
I was trying to write a piece of code that would work with any descriptors, as OpenCV has multiple cv::DescriptorExtractors implemented. The thing is, since I want to someday be able to make my own, OpenCV independent libraries that work with my descriptor interfaces, I wanted all the descriptors in std::vector<vector<double> > structures.
Here is my code that converts cv::Mat descOld to std::vector< std::vector <double> > desc:
cv::DescriptorExtractor *descCalc;
// initialize descCalc
descCalc->compute(*image, feats, descOld);
// conversion to std::vector<std::vector <double> > :
const double *temp;
desc.clear();
desc.reserve(descOld.cols);
for (int i=0, szi = this->desc.rows; i < szi; ++i){
temp = descOld.ptr<double>(i);
desc.push_back(std::vector<double>(temp, temp+descOld.cols));
}
assert(desc.size() == descOld.rows);
assert(desc[0].size() == descOld.cols);
Hope it helps some.