Python: How to do several float formattings with 1 lambda function - python

I have a numpy array
[2.15295647e+01, 8.12531501e+00, 3.97113829e+00, 1.00777250e+01]
and would like to format it so that it looks like this
[21.53, 08.13, 03.97, 10.08]
float_formatter = lambda x: "%.2f" % x
np.set_printoptions(formatter={'float_kind':float_formatter})
How can I adjust this to contain 2 float manipulations?
I need something like %02d %.2f % (x,y) but don't know how to change the lambda function to do this.

From what I understand, you just want your array values to be padded with two leading zeros and printed to two decimal places. All you need to do is modify the formatting string:
In [1]: "%05.2f" %np.pi
Out[1]: '03.14'
To break this down, the 5 means that the total length of the formatted string is 5 characters (including the decimal point), the 0 means that you want to pad with leading zeros, and the .2 means that you want two figures after the decimal point.
So if you wanted, say, 3 leading zeros and 4 decimal places you would do:
In [2]: "%08.4f" %np.pi
Out[2]: '003.1416
If you just wanted to pad with leading spaces rather than zeros, you can omit the 0 in front of the total length:
In [3]: "%8.4f" %np.pi
Out[3]: ' 3.1416'
There are other options that you can read about in the table of conversion flags here.
To set this as your new formatter, you would just do:
In [4]: float_formatter = lambda x: "%05.2f" %x
In [5]: np.set_printoptions(formatter={'float_kind':float_formatter})

If you want to work with two floats in your lambda, you need two input arguments like this:
float_formatter = lambda x, y: "%.2f %.2f" % (x, y)
You can define multiple inputs to lambda expressions, not just a single and the name is arbitrary. Here's the same thing with different argument names.
float_formatter = lambda float_one, float_two: "%.2f %.2f" % (float_one, float_two)

To change the values in the list you could use a list comprehension. Python 3 example below.
import numpy as np
precision = 2
formatter = "{0:."+str(precision)+"f}"
a = np.array([2.15295647e+01, 8.12531501e+00, 3.97113829e+00, 1.00777250e+01])
aFormat = np.array([float(formatter.format(i)) for i in a])
print(a, aFormat)
I first tried epileptic fish's option, but the printer function doesn't give you an array. It just gives you a float. So if you really want to change the print option for a 2d numpy matrix you will have to define your own function with an external counter on what to format which value with. The example below shows this with a class, because you don't want the external counter to be a global.
import numpy
class npPrint(object):
def __init__(self):
self.counter = 0
self.precision = 2
# end Constructor
def printer(self, x):
self.precision = 2
if self.counter == 0:
formatter = "{0:."+str(self.precision)+"f}"
self.counter += 1
else:
formatter = "{0:0"+str(self.precision)+"d}"
x = int(round(x))
self.counter = 0
return formatter.format(x)
# end printer
formatter = npPrint()
a = numpy.array([[2.15295647e+01, 8.12531501e+00], [3.97113829e+00, 1.00777250e+01]])
numpy.set_printoptions(formatter={"float_kind": lambda x, f=formatter: f.printer(x)})
print(a)
You have to have a counter, because you don't know if you are handed the x value or the y value. You just receive a float. This is really ugly. If I were you I would handle the printing myself and break apart the 2d matrix.

Related

Python Creating a function with unkown number arguments with splat operator

I am am trying to round numbers in a dataframe that has lists as values for each row. I need whole numbers to have no decimal and floats to only have two places after the decimal. There is an unknown number of values for each list (some lists have 2 values, some have 4 or 5 or more). Here is what I have:
df = pd.DataFrame({"A": [[16.0, 24.4175], [14.9687, 16.06], [22.75, 23.00]]})
def remove_exponent(num):
return num.to_integral() if num == num.to_integral() else num.normalize()
def round_string_float(x):
try:
return remove_exponent(Decimal(x).quantize(TWOPLACES))
except:
return x
df['A']=df['A'].apply(lambda x: [round_string_float(num) for num in x])
But this gives me: [Decimal('16'), Decimal('24.42')]
Here is what I am trying:
def round(num):
if str(numbers).find('/') > -1:
nom, den = numbers.split(',')
number=round_string_float(nom)
second=round_string_float(den)
return f'[{number}, {second}]'
but there has to be an easier way to do this
Here is what I want:
df = pd.DataFrame({"A": [[16, 24.42], [14.97, 16.06], [22.75, 23]]})
I would like to know have to use **args to do this but really anything that works would be good
Have you tried a for loop. For example
list = []
for i in range(len(df)):
for j in range(len(df[i])):
list .append(round(df[i][j]))
That's a weird format for a DataFrame, but if you want it you can do something like this:
import pandas as pd
df = pd.DataFrame({"A": [[16.0, 24.4175], [14.9687, 16.06], [22.75, 23.00]]})
print(df.applymap(lambda x: [round(v, None if v.is_integer() else 2) for v in x]))
Given that
The return value [of round] is an integer if ndigits is omitted or None.
this evaluates, for each nested number v, round(v) if v is an integer else round(v, 2).
This outputs
A
0 [16, 24.42]
1 [14.97, 16.06]
2 [22.75, 23]
I created an answer to this question that goes above and beyond what I wanted but I think it will help anyone looking for something similar. The problem with my company is we have to upload lists as values in a dataframe to the database. This is why the code is so ad-hoc:
from decimal import *
TWOPLACES = Decimal(10) ** -2
from natsort import natsorted
import ast
from fractions import Fraction
#----------------------------------------------------------------
# remove_exponent and round string float are designed to round whole numbers 16.00 to 16, and rounds numbers with 3 or more decimals to 2 decimals 16.254 to 16.25
def remove_exponent(num):
return num.to_integral() if num == num.to_integral() else num.normalize()
def round_string_float(x):
try:
return remove_exponent(Decimal(x).quantize(TWOPLACES))
except:
return x
#------------------------------------------------------------------------------
# frac2string converts fractions to decimals: 1 1/2 to 1.5
def frac2string(s):
i, f = s.groups(0)
f = round_string_float(Fraction(f))
return str(int(i) + round_string_float(float(f)))
#------------------------------------------
#remove duplicates is self explanitory
def remove_duplicates(A):
[A.pop(count) for count,elem in enumerate(A) if A.count(elem)!=1]
return A
# converts fractions and rounds numbers
df['matches'] = df['matches'].apply(lambda x:[re.sub(r'(?:(\d+)[-\s])?(\d+/\d+)', frac2string, x)])
# removes duplicates( this needs to be in the format ["\d","\d"]
df['matches'] = df['matches'].apply(lambda x: remove_duplicates([n.strip() for n in ast.literal_eval(x)]))

Taking a 8 bit number and split them into two 4 bit numbers

I have an integer integer = 10101001. I wanted to split that number into an array of 2 four bit numbers array = [1010,1001]. How do I do this? Are there any python methods?
This is a way to do it:
num = 10101001
str_num = str(num)
split_num = [int(str_num[0:4]), int(str_num[4:])]
print(split_num)
Output:
[1010, 1001]
You need to pass by the string version of you int
i = 10101001
str_i = str(i)
res = str_i[:len(str_i) // 2], str_i[len(str_i) // 2:]
print(res) # ('1010', '1001')
If that is indeed the general case, you can use a simple method.
def func(x):
x = str(x) # this takes x and turns it into a string
sub1 = int(x[:4]) # this takes the first 4 digits and turns it into an integer
sub2 = int(x[4:]) # this takes the last 4 digits and turns it into an integer
return [sub1, sub2]
Note that I used the fact that strins are subscriptable. You can fetch characters in a string just like a list.

Formatting number in Python according to culture code

Im trying to find a way to format number in Python according to the culture code used.
In R, for example, there is a function called 'formatC' that does exactly what i need:
if the culture code is 'en-US' the decimal mark will be ',' and the decimal mark, '.' (ex: 1,000.00) and, if the culture code is 'pt-BR', we would have 1.000,00.
Now, Im trying to do this in Python.. idk if there is a function that already does that... Can someone help me?
You can use python's built in 'locale' module. I would have a look through the docs here: https://docs.python.org/2/library/locale.html, but for your example you can do something like this:
import locale
#note the underscore rather than -
locale.setlocale(locale.LC_ALL, 'pt_BR')
print(locale.currency(1000.00, False))
#prints '1000,00'
Using locale you will be able to format a wide range of values to suit specific locations, not just currency!
You want the locale package, it has functions for doing locale specific formating:
https://docs.python.org/3.8/library/locale.html
This is a function which takes the number, d1 =',' and d2 ='.' for example and outputs the number in the desired format as a string
def formatC (number, d1, d2):
real_part = int (number)
rest = str(number-int(number))[2:]
real_part_as_string = str (real_part)
k = 0
result = ''
for i in range (len(real_part_as_string)-1, -1, -1):
k = k+1
result = real_part_as_string [i] + result
if (k % 3 == 0 and i != 0):
result = d1+result
k = 0
if (not rest):
return result
return result + d2 + str (rest)
I don't know if this is exactly what is asked for because this returns a string.
[edited]
Formatting an array:
def formatArray (array, d1, d2):
for element in array:
print (formatC (element, d1, d2))
Example input:
formatArray ([1200.0, 12346], ',', '.')

Python (lambda?) random number generation

I have a string where I want to output random ints of differing size using Python's built-in format function.
IE: "{one_digit}:{two_digit}:{one_digit}"
Yields: "3:27:9"
I'm trying:
import random
"{one_digit}:{two_digit}:{one_digit}".format(one_digit=random.randint(1,9),two_digits=random.randint(10,99))
but this always outputs...
"{one_digit}:{two_digit}:{one_digit}".format(one_digit=random.randint(1,9),two_digit=random.randint(10,99))
>>>'4:22:4'
"{one_digit}:{two_digit}:{one_digit}".format(one_digit=random.randint(1,9),two_digit=random.randint(10,99))
>>>'7:48:7'
"{one_digit}:{two_digit}:{one_digit}".format(one_digit=random.randint(1,9),two_digit=random.randint(10,99))
>>>'2:28:2'
"{one_digit}:{two_digit}:{one_digit}".format(one_digit=random.randint(1,9),two_digit=random.randint(10,99))
>>>'1:12:1'
Which is as expected since the numbers are evaluated before hand. I'd like them to all be random, though. I tried using a lambda function but only got this:
"test{number}:{number}".format(number=lambda x: random.randint(1,10))
But that only yields
"test{number}:{number}".format(number=lambda x: random.randint(1,10))
>>>'test<function <lambda> at 0x10aa14e18>:<function <lambda> at 0x10aa14e18>'
First off: str.format is the wrong tool for the job, because it doesn't allow you to generate a different value for each replacement.
The correct solution is therefore to implement your own replacement function. We'll replace the {one_digit} and {two_digit} format specifiers with something more suitable: {1} and {2}, respectively.
format_string = "{1}:{2}:{1}"
Now we can use regex to substitute all of these markers with random numbers. Regex is handy because re.sub accepts a replacement function, which we can use to generate a new random number every time:
import re
def repl(match):
num_digits = int(match.group(1))
lower_bound = 10 ** (num_digits - 1)
upper_bound = 10 * lower_bound - 1
random_number = random.randint(lower_bound, upper_bound)
return str(random_number)
result = re.sub(r'{(\d+)}', repl, format_string)
print(result) # result: 5:56:1
How about this?
import random
r = [1,2,3,4,5]
','.join(map(str,(random.randint(-10**i,10**i) for i in r)))
The first two params(-10** i, 10**i) are low and upper bound meanwhile size=10 is the amount of numbers).
Example output: '-8,45,-328,7634,51218'
Explanation:
It seems you are looking to join random numbers with ,. This can simply be done using ','.join([array with strings]), e.g. ','.join(['1','2']) which would return '1,2'.
What about This?
'%s:%s:%s' % (random.randint(1,9),random.randint(10,99),random.randint(1,9))
EDIT : meeting requirements.
a=[1,2,2,1,3,4,5,9,0] # our definition of the pattern (decimal range)
b= ''
for j in enumerate(a):
x=random.randint(10**j,10**(j+1)-1)
b = b + '%s:' % x
print(b)
sample:
print (b)
31:107:715:76:2602:99021:357311:7593756971:1:

Generating a Random Hex Color in Python

For a Django App, each "member" is assigned a color to help identify them. Their color is stored in the database and then printed/copied into the HTML when it is needed. The only issue is that I am unsure how to generate random Hex colors in python/django. It's easy enough to generate RGB colors, but to store them I would either need to a) make three extra columns in my "Member" model or b) store them all in the same column and use commas to separate them, then, later, parse the colors for the HTML. Neither of these are very appealing, so, again, I'm wondering how to generate random Hex colors in python/django.
import random
r = lambda: random.randint(0,255)
print('#%02X%02X%02X' % (r(),r(),r()))
Here is a simple way:
import random
color = "%06x" % random.randint(0, 0xFFFFFF)
To generate a random 3 char color:
import random
color = "%03x" % random.randint(0, 0xFFF)
%x in C-based languages is a string formatter to format integers as hexadecimal strings while 0x is the prefix to write numbers in base-16.
Colors can be prefixed with "#" if needed (CSS style)
little late to the party,
import random
chars = '0123456789ABCDEF'
['#'+''.join(random.sample(chars,6)) for i in range(N)]
Store it as a HTML color value:
Updated: now accepts both integer (0-255) and float (0.0-1.0) arguments. These will be clamped to their allowed range.
def htmlcolor(r, g, b):
def _chkarg(a):
if isinstance(a, int): # clamp to range 0--255
if a < 0:
a = 0
elif a > 255:
a = 255
elif isinstance(a, float): # clamp to range 0.0--1.0 and convert to integer 0--255
if a < 0.0:
a = 0
elif a > 1.0:
a = 255
else:
a = int(round(a*255))
else:
raise ValueError('Arguments must be integers or floats.')
return a
r = _chkarg(r)
g = _chkarg(g)
b = _chkarg(b)
return '#{:02x}{:02x}{:02x}'.format(r,g,b)
Result:
In [14]: htmlcolor(250,0,0)
Out[14]: '#fa0000'
In [15]: htmlcolor(127,14,54)
Out[15]: '#7f0e36'
In [16]: htmlcolor(0.1, 1.0, 0.9)
Out[16]: '#19ffe5'
This has been done before. Rather than implementing this yourself, possibly introducing errors, you may want to use a ready library, for example Faker. Have a look at the color providers, in particular hex_digit.
In [1]: from faker import Factory
In [2]: fake = Factory.create()
In [3]: fake.hex_color()
Out[3]: u'#3cae6a'
In [4]: fake.hex_color()
Out[4]: u'#5a9e28'
Just store them as an integer with the three channels at different bit offsets (just like they are often stored in memory):
value = (red << 16) + (green << 8) + blue
(If each channel is 0-255). Store that integer in the database and do the reverse operation when you need to get back to the distinct channels.
import random
def hex_code_colors():
a = hex(random.randrange(0,256))
b = hex(random.randrange(0,256))
c = hex(random.randrange(0,256))
a = a[2:]
b = b[2:]
c = c[2:]
if len(a)<2:
a = "0" + a
if len(b)<2:
b = "0" + b
if len(c)<2:
c = "0" + c
z = a + b + c
return "#" + z.upper()
So many ways to do this, so here's a demo using "colorutils".
pip install colorutils
It is possible to generate random values in (RGB, HEX, WEB, YIQ, HSV).
# docs and downloads at
# https://pypi.python.org/pypi/colorutils/
from colorutils import random_web
from tkinter import Tk, Button
mgui = Tk()
mgui.geometry('150x28+400+200')
def rcolor():
rn = random_web()
print(rn) # for terminal watchers
cbutton.config(text=rn)
mgui.config(bg=rn)
cbutton = Button(text="Click", command=rcolor)
cbutton.pack()
mgui.mainloop()
I certainly hope that was helpful.
import secrets
# generate 4 sets of 2-digit hex chars for a color with transparency
rgba = f"#{secrets.token_hex(4)}" # example return: "#ffff0000"
# generate 3 sets of 2-digit hex chars for a non-alpha color
rgb = f"#{secrets.token_hex(3)}" # example return: "#ab12ce"
import random
def generate_color():
color = '#{:02x}{:02x}{:02x}'.format(*map(lambda x: random.randint(0, 255), range(3)))
return color
Basically, this will give you a hashtag, a randint that gets converted to hex, and a padding of zeroes.
from random import randint
color = '#{:06x}'.format(randint(0, 256**3))
#Use the colors wherever you need!
For generating random anything, take a look at the random module
I would suggest you use the module to generate a random integer, take it's modulo 2**24, and treat the top 8 bits as R, that middle 8 bits as G and the bottom 8 as B.
It can all be accomplished with div/mod or bitwise operations.
hex_digits = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
digit_array = []
for i in xrange(6):
digit_array.append(hex_digits[randint(0,15)])
joined_digits = ''.join(digit_array)
color = '#' + joined_digits
import random
def get_random_hex:
random_number = random.randint(0,16777215)
# convert to hexadecimal
hex_number = str(hex(random_number))
# remove 0x and prepend '#'
return'#'+ hex_number[2:]
Would like to improve upon this solution as I found that it could generate color codes that have less than 6 characters. I also wanted to generate a function that would create a list that can be used else where such as for clustering in matplotlib.
import random
def get_random_hex:
random_number = random.randint(0,16777215)
# convert to hexadecimal
hex_number = str(hex(random_number))
# remove 0x and prepend '#'
return'#'+ hex_number[2:]
My proposal is :
import numpy as np
def color_generator (no_colors):
colors = []
while len(colors) < no_colors:
random_number = np.random.randint(0,16777215)
hex_number = format(random_number, 'x')
if len(hex_number) == 6:
hex_number = '#'+ hex_number
colors.append (hex_number)
return colors
Here's a simple code that I wrote based on what hexadecimal color notations represent:
import random
def getRandomCol():
r = hex(random.randrange(0, 255))[2:]
g = hex(random.randrange(0, 255))[2:]
b = hex(random.randrange(0, 255))[2:]
random_col = '#'+r+g+b
return random_col
The '#' in the hexadecimal color code just represents that the number represented is just a hexadecimal number. What's important is the next 6 digits. Pairs of 2 digits in those 6 hexadecimal digits represent the intensity of RGB (Red, Green, and Blue) each. The intensity of each color ranges between 0-255 and a combination of different intensities of RGB produces different colors.
For example, in #ff00ff, the first ff is equivalent to 255 in decimal, the next 00 is equivalent to 0 in decimal, and the last ff is equivalent to 255 in decimal. Therefore, #ff00ff in hexadecimal color coding is equivalent to RGB(255, 0, 255).
With this concept, here's the explanation of my approach:
Generated intensities of random numbers for each of r, g
and b
Converted those intensities into hexadecimal
Ignored the first 2 characters of each hexadecimal value '0x'
Concatenated '#' with the hexadecimal values r, g and b
intensities.
Feel free to refer to this link if you wanna know more about how colors work: https://hackernoon.com/hex-colors-how-do-they-work-d8cb935ac0f
Cheers!
Hi, maybe i could help with the next function that generate random Hex colors :
from colour import Color
import random as random
def Hex_color():
L = '0123456789ABCDEF'
return Color('#'+ ''.join([random.choice(L) for i in range(6)][:]))
from random import randbytes
randbytes(3).hex()
output
f5f2c9
There are a lot of complex answers here, this is what I used for a code of mine using one import line and one line to get a random code:
import random
color = '#' + ''.join(random.choices('0123456789ABCDEF', k=6))
print(color)
The output will be something like:
#3F67CD
If you want to make a list of color values, let's say, of 10 random colors, you can do the following:
import random as r
hex_chars = '0123456789ABCDEF'
num_colors = 10
colors = ['#' + ''.join(r.choices(hex_chars, k=6)) for _ in range(num_colors)]
print(colors)
And the output will be a list containing ten different random colors:
['#3DBEA2', '#0B3B64', '#31D196', '#6A98C2', '#9C1712', '#73AFFE', '#9F5E0D', '#A2F07E', '#EB6407', '#7E8FB6']
I hope that helps!

Categories

Resources